// dbOperation
// 数据库操作单元

package main

import (
	"errors"
	"fmt"
	mgo "gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"strconv"
	"strings"
	"time"

	"server/src/gps"
	"server/src/protocol808"
	//"smartu365.com/protocol808"
)

// 数据库操作类
type DBOperation struct {
	session        *mgo.Session
	dbName         string
	exportMaxCount int //导出数据的最大纪录数
	//serialNo       uint16 //消息流水号
}

// 表名
const (
	CollectionLastStatuses string = "laststatuses"
	CollectionReceivers    string = "receivers"
	CollectionPositions    string = "positions"
	CollectionTireRawDatas string = "tirerawdatas"
	CollectionTireDatas    string = "tiredatas"
	CollectionCustomers    string = "customers"
	CollectionCompanies    string = "companies"
	CollectionTeams        string = "teams"
	// CollectionTeamDeleted            string = "teamdeleted"
	CollectionDrivers                string = "drivers"
	CollectionRelations              string = "relations"
	CollectionTires                  string = "tires"
	CollectionTireModels             string = "tiremodels"
	CollectionTireBrands             string = "tirebrands"
	CollectionVehicles               string = "vehicles"
	CollectionOrganizationProperties string = "organizationproperties"
	CollectionTireWarnings           string = "tirewarnings"
	CollectionMileageStatistics      string = "mileagestatistics"
	CollectionTimeStatistics         string = "timestatistics"
	CollectionEquipmentExchanges     string = "equipmentexchanges"
	CollectionEquipmentInvalids      string = "equipmentinvalids"
	CollectionSensors                string = "sensors"
	CollectionLoginHistories         string = "loginhistories"
	CollectionTireWarningStatistics  string = "tirewarningstatistics"
	CollectionRawDatas               string = "rawdatas"
	CollectionTrackDates             string = "trackdates"
	CollectionCommands               string = "commands"
	CollectionWarningDeals           string = "warningdeals"
	CollectionVehicleBrands          string = "vehiclebrands"
	CollectionTireMaintains          string = "tiremaintains"
	CollectionTireFixes              string = "tirefixes"     //补胎表
	CollectionTireExchanges          string = "tireexchanges" //换胎表
	CollectionTireFixValves          string = "tirefixvalves" //换气门嘴表
	CollectionTireInflates           string = "tireinflates"  //加气表
	CollectionMaintenanceSites       string = "maintenancesites"
	CollectionEquipmentInstalls      string = "equipmentinstalls"
	CollectionVehicleChecks          string = "vehiclechecks"
	CollectionWarehouses             string = "warehouses"
	CollectionTireActions            string = "tireactions"
	CollectionReportAccidents        string = "reportaccident"  //报障表
	CollectionOrderProgresses        string = "orderprogresses" //订单进程表
	CollectionWorkOrders             string = "workorders"      // 工单表

)

const (
	UserTypeAdministrator  int = 0
	UserTypeTeamLeader     int = 1
	UserTypeDriver         int = 2
	UserTypeIndividual     int = 3
	UserTypeToolUser       int = 4
	UserTypeGuest          int = 5
	UserTypeMineStaff      int = 6
	UserTypeMineTireWorker int = 7
	UserTypeSystemUser     int = 100
)

const (
	GpsWGS84 string = "wgs"
	GpsGCJ02 string = "gcj"
	GpsBd09  string = "bd"
)

const (
	ReceiverStatusNotActivated int = 0
	ReceiverStatusOnline       int = 1
	ReceiverStatusOffline      int = -1
	ReceiverStatusInvalid      int = -2
)

const (
	TireStatusUnknow  int = -1
	TireStatusNew     int = 0
	TireStatusReuse   int = 1
	TireStatusRenew   int = 2
	TireStatusScrapt  int = 3
	TireStatusNeedFix int = 4
)

const (
	TireActionStockIn  int = 1
	TireActionStockOut int = 2
	TireActionGetOn    int = 3
	TireActionCheck    int = 4
	TireActionGetOff   int = 5
	TireActionScrap    int = 6
	TireActionBind     int = 7
	TireActionUnbind   int = 8
	TireActionEdit     int = 9
	TireActionFix      int = 10
	TireActionFixValve int = 11
	TireActionInflate  int = 12
	TireActionOther    int = 100
)

const TokenExpire int64 = 24 * 60 * 60

const ReceiverOfflineInterval int64 = 24 * 60 * 60
const SensorOfflineInterval int64 = 24 * 60 * 60

func NewDBOperation(cfg *Config) (*DBOperation, error) {
	session, err := mgo.Dial(cfg.DBUrl)
	if err != nil {
		return nil, err
	}

	dbo := DBOperation{session: session, dbName: cfg.DBName, exportMaxCount: cfg.ExportMaxCount}

	return &dbo, nil
}

func (p *DBOperation) Close() {
	p.session.Close()
}

type UserTokenT struct {
	TokenExpire int64 `bson:"tokenexpire"`
}

// 验证AccessToken
func (p *DBOperation) checkAccessToken(userid string, token string) bool {
	s := p.session.Copy()
	defer s.Close()

	oi := bson.ObjectIdHex(userid)
	c := s.DB(p.dbName).C(CollectionCustomers)
	var ut UserTokenT

	err := c.Find(bson.M{"_id": oi, "token": token}).Select(bson.M{"tokenexpire": 1}).One(&ut)
	if err != nil {
		return false
	}

	if time.Now().Unix()-ut.TokenExpire > TokenExpire {
		return false
	}
	return true
}

type CustomerTypeT struct {
	Utype int    `bson:"utype"`
	Cid   int    `bson:"cid"`
	Tid   string `bson:"tid"`
}

func (p *DBOperation) userReceivers(userid string, rid string) []string {
	s := p.session.Copy()
	defer s.Close()

	var ct CustomerTypeT
	oi := bson.ObjectIdHex(userid)
	c := s.DB(p.dbName).C(CollectionCustomers)
	err := c.Find(bson.M{"_id": oi}).Select(bson.M{"_id": 0, "utype": 1, "cid": 1, "tid": 1 /*, "rids": 1*/}).One(&ct)
	if err == nil {
		if ct.Utype == UserTypeMineStaff || ct.Utype == UserTypeMineTireWorker {
			ct.Utype = UserTypeTeamLeader
		}

		if ct.Utype == UserTypeSystemUser || ct.Utype == UserTypeToolUser {
			return p.allReceivers(rid)
		} else if ct.Utype == UserTypeAdministrator {
			if ct.Cid != 0 {
				return p.companyReceivers(ct.Cid, rid)
			}
		} else if ct.Utype == UserTypeTeamLeader {
			if ct.Tid != "" {
				return p.teamReceivers(ct.Tid, rid)
			}
		} else if ct.Utype == UserTypeIndividual || ct.Utype == UserTypeDriver {
			return nil
		}
	}

	return nil
}

func (p *DBOperation) userReceiversEx(userid string, cid int, tid string, rid string) []string {
	var rids []string
	userType := p.userType(userid)
	if userType != UserTypeSystemUser {
		if tid != "" {
			rids = p.teamReceivers(tid, rid)
		} else {
			rids = p.companyReceivers(cid, rid)
		}
	} else {
		if tid != "" {
			rids = p.teamReceivers(tid, rid)
		} else if cid != 0 {
			rids = p.companyReceivers(cid, rid)
		} else {
			rids = p.allReceivers(rid)
		}
	}

	return rids
}

func (p *DBOperation) getReceivers(userid string, cid int, tid string, rid string) []string {
	rids := make([]string, 0)

	if userid != "" {
		ut := p.userType(userid)
		if ut != UserTypeSystemUser && cid == 0 {
			return rids
		}
	}

	var queryRes []map[string]string
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	bsonQuery := bson.M{}
	if cid != 0 {
		bsonQuery["cid"] = cid
	}
	if tid != "" {
		bsonQuery["tids"] = tid
	}
	if rid != "" {
		bsonQuery["rid"] = bson.RegEx{Pattern: rid, Options: "im"}
	}
	err := c.Find(bsonQuery).Select(bson.M{"_id": 0, "rid": 1}).All(&queryRes)
	if err != nil || len(queryRes) == 0 {
		return rids
	}
	for _, v := range queryRes {
		if v["rid"] != "" {
			rids = append(rids, v["rid"])
		}
	}

	return rids
}

func (p *DBOperation) getReceiversOfTeam(cid int, tid string) ([]string, error) {
	rids := make([]string, 0)

	if cid == 0 && tid == "" {
		return rids, nil
	}

	var queryRes []map[string]string
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	bsonQuery := bson.M{}

	if cid != 0 {
		bsonQuery["cid"] = cid
	}
	if tid != "" {
		bsonQuery["tids"] = tid
	}
	bsonQuery["$or"] = []bson.M{
		{"status": 1},
		{"status": -1},
	}
	err := c.Find(bsonQuery).Select(bson.M{"_id": 0, "rid": 1}).All(&queryRes)
	if err != nil || len(queryRes) == 0 {
		return rids, errors.New("没有设备")
	}
	for _, v := range queryRes {
		if v["rid"] != "" {
			rids = append(rids, v["rid"])
		}
	}

	return rids, nil
}

func (p *DBOperation) allReceivers(rid string) []string {
	s := p.session.Copy()
	defer s.Close()

	var recevers []string = make([]string, 0)
	var res []map[string]string
	var err error

	c := s.DB(p.dbName).C(CollectionReceivers)
	if rid == "" {
		err = c.Find(nil).Select(bson.M{"_id": 0, "rid": 1}).All(&res)
	} else {
		err = c.Find(bson.M{"rid": bson.RegEx{Pattern: rid, Options: "im"}}).Select(bson.M{"_id": 0, "rid": 1}).All(&res)
	}
	if err == nil {
		for _, v := range res {
			recevers = append(recevers, v["rid"])
		}
	}

	return recevers
}

func (p *DBOperation) companyReceivers(companyId int, rid string) []string {
	s := p.session.Copy()
	defer s.Close()

	var res []map[string]string
	var ret []string
	var sRid string

	c := s.DB(p.dbName).C(CollectionOrganizationProperties)
	err := c.Find(bson.M{"cid": companyId, "rid": bson.M{"$exists": 1}}).Select(bson.M{"rid": 1, "_id": 0}).All(&res)
	if err != nil {
		return nil
	}
	ret = make([]string, 0)
	for _, v := range res {
		sRid = v["rid"]
		if sRid != "" {
			if rid != "" {
				if strings.Contains(sRid, rid) {
					ret = append(ret, sRid)
				}
			} else {
				ret = append(ret, sRid)
			}
		}
	}
	return ret
}

func (p *DBOperation) teamReceivers(teamId string, rid string) []string {
	if !bson.IsObjectIdHex(teamId) {
		return nil
	}

	s := p.session.Copy()
	defer s.Close()

	var res []map[string]string
	var ret []string
	var sRid string

	c := s.DB(p.dbName).C(CollectionOrganizationProperties)
	err := c.Find(bson.M{"tid": teamId, "rid": bson.M{"$exists": 1}}).Select(bson.M{"rid": 1, "_id": 0}).All(&res)
	if err != nil {
		return nil
	}
	ret = make([]string, 0)
	for _, v := range res {
		sRid = v["rid"]
		if sRid != "" {
			if rid != "" {
				if strings.Contains(sRid, rid) {
					ret = append(ret, sRid)
				}
			} else {
				ret = append(ret, sRid)
			}
		}
	}
	return ret
}

func (p *DBOperation) userHaveReceiver(userid string, receiverid string) bool {
	s := p.session.Copy()
	defer s.Close()

	var ct CustomerTypeT
	oi := bson.ObjectIdHex(userid)
	c := s.DB(p.dbName).C(CollectionCustomers)
	err := c.Find(bson.M{"_id": oi}).Select(bson.M{"_id": 0, "utype": 1, "cid": 1, "tid": 1 /*, "rids": 1*/}).One(&ct)
	if err == nil {
		if ct.Utype == UserTypeMineStaff || ct.Utype == UserTypeMineTireWorker {
			ct.Utype = UserTypeTeamLeader
		}

		if ct.Utype == UserTypeSystemUser {
			return true
		} else if ct.Utype == UserTypeAdministrator {
			if ct.Cid != 0 {
				return p.companyHaveReceiver(ct.Cid, receiverid)
			}
		} else if ct.Utype == UserTypeTeamLeader {
			if ct.Tid != "" {
				return p.teamHaveReceiver(ct.Tid, receiverid)
			}
		} else if ct.Utype == UserTypeIndividual || ct.Utype == UserTypeDriver {
			return false
		}
	}

	return false
}

func (p *DBOperation) companyHaveReceiver(companyid int, receiverid string) bool {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionOrganizationProperties)
	var res interface{}

	err := c.Find(bson.M{"cid": companyid, "rid": receiverid}).Select(bson.M{"_id": 1}).One(&res)
	return err == nil
}

func (p *DBOperation) teamHaveReceiver(teamid string, receiverid string) bool {
	if !bson.IsObjectIdHex(teamid) {
		return false
	}
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionOrganizationProperties)
	var res interface{}

	err := c.Find(bson.M{"tid": teamid, "rid": receiverid}).Select(bson.M{"_id": 1}).One(&res)
	return err == nil
}

func (p *DBOperation) haveReceiver(cid int, tid string, rid string) bool {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)

	bsonQuery := bson.M{"rid": rid}
	if tid != "" {
		bsonQuery["tids"] = tid
	} else {
		bsonQuery["cid"] = cid
	}

	err := c.Find(bsonQuery).Select(bson.M{"_id": 1}).One(nil)
	return err == nil
}

func (p *DBOperation) receiverBatchCreate(iType int, prefix string, startNumber int, endNumber int) (count int, failedCount int, faileds []string) {
	s := p.session.Copy()
	defer s.Close()

	var rid string
	var err error
	faileds = make([]string, 0)

	c := s.DB(p.dbName).C(CollectionReceivers)
	for number := startNumber; number <= endNumber; number++ {
		count++
		rid = fmt.Sprintf("%s%04d", prefix, number)

		err = c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 1}).One(nil)
		if err == nil {
			failedCount++
			faileds = append(faileds, rid)
		} else {
			err = c.Insert(bson.M{"rid": rid, "type": iType, "status": 0})
			if err != nil {
				failedCount++
				faileds = append(faileds, rid)
			}
		}
	}

	return
}

type ReceiverT struct {
	Rid         string `bson:"rid" json:"rid"`
	Type        int    `bson:"type" json:"type"`
	Plate       string `bson:"plate" json:"plate"`
	Vid         string `json:"-"`
	Status      int    `bson:"status" json:"status"`
	Lt          int64  `bson:"lt" json:"lt"`
	Driver      string `json:"driver"`
	DriverPhone string `json:"driverphone"`
	Team        string `json:"team"`
}

func (p *DBOperation) receivers(userid string, rid string, page int) []ReceiverT { //[]map[string]interface{} {
	s := p.session.Copy()
	defer s.Close()

	//每页20条纪录
	const PageCount int = 20

	rids := p.userReceivers(userid, rid)

	var res []ReceiverT
	var tid string

	if rids != nil {
		c := s.DB(p.dbName).C(CollectionReceivers)
		status := []int{1, -1}
		c.Find(bson.M{"rid": bson.M{"$in": rids}, "status": bson.M{"$in": status}}).Select(bson.M{"_id": 0, "rid": 1, "type": 1, "vid": 1, "status": 1, "lt": 1}).
			Sort("-lt", "rid").Skip(page * PageCount).Limit(PageCount).All(&res)
		t := time.Now().Unix()
		for i := 0; i < len(res); i++ {
			res[i].Plate, res[i].Driver, res[i].DriverPhone, tid, _, _ = p.getPlateByVid(res[i].Vid)
			res[i].Team = p.getTeamName(tid)
			if res[i].Status != -2 {
				if t-res[i].Lt > ReceiverOfflineInterval {
					res[i].Status = -1
				} else {
					res[i].Status = 1
				}
			}
		}
	}
	return res
}

func (p *DBOperation) receiversV2(userid string, rid string, page int) []ReceiverT { //[]map[string]interface{} {
	const PageCount int = 20

	oid := bson.ObjectIdHex(userid)

	s := p.session.Copy()
	defer s.Close()

	var userInfo struct {
		UserType int    `bson:"utype"`
		Cid      int    `bson:"cid"`
		Tid      string `bson:"tid"`
	}

	c := s.DB(p.dbName).C(CollectionCustomers)
	err := c.Find(bson.M{"_id": oid}).Select(bson.M{"_id": 0, "cid": 1, "tid": 1, "utype": 1}).One(&userInfo)
	if err != nil {
		return nil
	}

	if userInfo.UserType == UserTypeSystemUser {
		userInfo.Cid = 0
		userInfo.Tid = ""
	}

	c = s.DB(p.dbName).C(CollectionReceivers)
	var res []ReceiverT

	status := []int{1, -1}
	bsonQuery := bson.M{}
	if userInfo.Tid != "" {
		bsonQuery["tids"] = userInfo.Tid
	} else if userInfo.Cid != 0 {
		bsonQuery["cid"] = userInfo.Cid
	}
	if rid != "" {
		bsonReg := bson.RegEx{Pattern: rid, Options: "im"}
		bsonQuery["$or"] = []bson.M{{"plate": bsonReg}, {"rid": bsonReg}}
	}
	bsonQuery["status"] = bson.M{"$in": status}

	err = c.Find(bsonQuery).Select(bson.M{"_id": 0, "rid": 1, "type": 1, "vid": 1, "plate": 1, "status": 1, "lt": 1}).
		Sort("-lt", "rid").Skip(page * PageCount).Limit(PageCount).All(&res)
	if err == nil {
		now := time.Now().Unix()
		var lt int64
		for i := 0; i < len(res); i++ {
			lt = p.getRidLastTime(res[i].Rid)
			if lt > 0 {
				if now-lt > ReceiverOfflineInterval {
					res[i].Status = -1
				} else {
					res[i].Status = 1
				}
			}
		}
	}

	return res
}

func (p *DBOperation) getPlateByVid(vid string) (string, string, string, string, string, int) {
	type PlateT struct {
		Plate       string `bson:"plate"`
		Driver      string `bson:"driver"`
		DriverPhone string `bson:"driverphone"`
		Tid         string `bson:"tid"`
		Type        int    `bson:"type"`
	}
	s := p.session.Copy()
	defer s.Close()

	var res PlateT //map[string]string
	c := s.DB(p.dbName).C(CollectionVehicles)
	err := c.Find(bson.M{"vid": vid}).Select(bson.M{"_id": 0, "plate": 1, "driver": 1, "driverphone": 1, "tid": 1, "type": 1}).One(&res)
	if err != nil {
		return "", "", "", "", "", 0
	}
	return res.Plate, res.Driver, res.DriverPhone, res.Tid, vid, res.Type
}

func (p *DBOperation) getPlateOnlyByRid(rid string) string {
	s := p.session.Copy()
	defer s.Close()

	var res map[string]string
	c := s.DB(p.dbName).C(CollectionReceivers)
	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "plate": 1}).One(&res)
	if err != nil {
		return ""
	}
	return res["plate"]
}

func (p *DBOperation) getPlateByRid(rid string) (string, string, string, string, string, int) {
	s := p.session.Copy()
	defer s.Close()

	var res map[string]string
	c := s.DB(p.dbName).C(CollectionReceivers)
	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "vid": 1}).One(&res)
	if err != nil {
		return "", "", "", "", "", 0
	}
	return p.getPlateByVid(res["vid"])
}

type ReceiverExT struct {
	Rid         string  `bson:"rid" json:"rid"`
	Type        int     `bson:"type" json:"type"`
	Plate       string  `json:"plate"`
	Vid         string  `bson:"vid" json:"vid"`
	Status      int     `bson:"status" json:"status"`
	Lt          int64   `bson:"lt" json:"lt"`
	Mileage     float64 `bson:"ma" json:"mileage"`
	Volume      int     `json:"volume"`
	Duration    int     `bson:"dur" json:"duration"`
	Iccid       string  `bson:"iccid" json:"iccid"`
	Driver      string  `json:"driver"`
	DriverPhone string  `json:"driverphone"`
	Team        string  `json:"team"`
}

func (p *DBOperation) receiverList(cid int, tid string, rid, iccid, plate string, online, page, export int) (int, []ReceiverExT) {
	s := p.session.Copy()
	defer s.Close()

	const PageCount int = 10
	var res []ReceiverExT
	var err error
	var total int
	var tid2 string

	c := s.DB(p.dbName).C(CollectionReceivers)

	bsonQuery := bson.M{}
	if cid != 0 {
		bsonQuery["cid"] = cid
	}
	if tid != "" {
		bsonQuery["tids"] = tid
	}
	if rid != "" {
		bsonQuery["rid"] = bson.RegEx{Pattern: rid, Options: "im"}
	}
	if iccid != "" {
		bsonQuery["iccid"] = bson.RegEx{Pattern: iccid, Options: "im"}
	}
	if plate != "" {
		bsonQuery["plate"] = bson.RegEx{Pattern: plate, Options: "im"}
	}
	if online != 0 {
		lt := time.Now().Unix() - ReceiverOfflineInterval
		if online == -1 {
			bsonQuery["lt"] = bson.M{"$lt": lt}
		} else if online == 1 {
			bsonQuery["lt"] = bson.M{"$gte": lt}
		}
	}

	total, err = c.Find(bsonQuery).Count()
	if err == nil && total > 0 {
		query := c.Find(bsonQuery).Select(bson.M{"_id": 0, "rid": 1, "type": 1, "vid": 1, "status": 1,
			"lt": 1, "ma": 1, "dur": 1, "iccid": 1})
		if export == 0 {
			err = query.Sort("-lt", "rid").Skip(page * PageCount).Limit(PageCount).All(&res)
		} else {
			err = query.Sort("rid").Limit(p.exportMaxCount).All(&res)
		}

		if err != nil {
			res = make([]ReceiverExT, 0)
		}

		t := time.Now().Unix()
		for i := 0; i < len(res); i++ {
			res[i].Plate, res[i].Driver, res[i].DriverPhone, tid2, _, _ = p.getPlateByVid(res[i].Vid)
			res[i].Team = p.getTeamName(tid2)
			res[i].Volume = p.receiverPower(res[i].Rid)
			if res[i].Status != -2 {
				if t-res[i].Lt > ReceiverOfflineInterval {
					res[i].Status = -1
				} else {
					res[i].Status = 1
				}
			}
		}
	}

	return total, res
}

func (p *DBOperation) receiverPower(rid string) int {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionLastStatuses)
	var res struct {
		Vol float32 `bson:"vol"`
	}
	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "vol": 1}).One(&res)
	if err == nil {
		if res.Vol <= 3.4 {
			return 0
		}

		return int((res.Vol - 3.4) * 1000 / 8)
	}

	return 0
}

type ReceiverViewT struct {
	Rid          string          `bson:"rid" json:"rid"`
	Type         int             `bson:"type" json:"type"`
	Plate        string          `json:"plate"`
	Lt           int64           `bson:"lt" json:"lt"`
	Team         string          `json:"team"`
	FixPress     float64         `bson:"fixpress" json:"-"`
	FixTemp      int             `bson:"fixtemp" json:"-"`
	LastPressure []LastPressureT `bson:"lp" json:"lp"`
	Cids         []int           `bson:"cids" json:"-"`
	Tids         []string        `bson:"tids" json:"-"`
}

func (p *DBOperation) receiverView(cid int, tid string, page, count int) (int, []ReceiverViewT) {
	s := p.session.Copy()
	defer s.Close()

	var res []ReceiverViewT
	var err error
	var total int

	c := s.DB(p.dbName).C(CollectionReceivers)

	bsonQuery := bson.M{}
	if cid != 0 {
		bsonQuery["cid"] = cid
	}
	if tid != "" {
		bsonQuery["tids"] = tid
	}
	bsonQuery["status"] = bson.M{"$in": []int{1, -1}}

	total, err = c.Find(bsonQuery).Count()
	if err == nil && total > 0 {
		query := c.Find(bsonQuery).Select(bson.M{"_id": 0, "rid": 1, "type": 1, "lt": 1, "fixpress": 1, "fixtemp": 1,
			"plate": 1, "cids": 1, "tids": 1})

		query.Sort("plate").Skip(page * count).Limit(count).All(&res)
		if len(res) > 0 {
			var gt, gp float64

			for i := 0; i < len(res); i++ {
				if res[i].Plate == "" {
					res[i].Plate = res[i].Rid
				}
				res[i].Team = p.getReceiverTeamName(res[i].Cids, res[i].Tids)
				res[i].LastPressure = p.getReceiverLastPressure(res[i].Rid)
				gt = float64(res[i].FixTemp)
				gp = res[i].FixPress * 14.504
				if gt != 0 && gp != 0 {
					for j := 0; j < len(res[i].LastPressure); j++ {
						res[i].LastPressure[j].ColdPres =
							p.calcColdPress(gt, float64(res[i].LastPressure[j].Temp), gp)
					}
				}
			}
		}
	}

	return total, res
}

func (p *DBOperation) getReceiverTeamName(cids []int, tids []string) string {
	size := len(tids)
	if size > 0 {
		return p.getTeamName(tids[size-1])
	}

	size = len(cids)
	if size > 0 {
		return p.getCompanyName(cids[size-1])
	}

	return ""
}

func (p *DBOperation) getReceiverLastPressure(rid string) []LastPressureT {
	type LastPressureAndWarningT struct {
		LastPressure []LastPressureT `bson:"lp"`
		LastWarning  []LastWarningT  `bson:"lw"`
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionLastStatuses)
	var res LastPressureAndWarningT //map[string][]LastPressureT
	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"lp": 1, "lw": 1}).One(&res)
	if err != nil {
		return nil
	}

	warn := ""
	for _, v := range res.LastWarning {
		if v.Stat == 0 {
			for i := 0; i < len(res.LastPressure); i++ {
				if v.CardId == res.LastPressure[i].CardId && v.SN == res.LastPressure[i].SN {
					warn = res.LastPressure[i].Warn
					if warn == "" {
						warn = strconv.Itoa(v.WType)
					} else {
						warn += warn + "," + strconv.Itoa(v.WType)
					}
					res.LastPressure[i].Warn = warn
				}
			}
		}
	}

	return res.LastPressure
}

func (p *DBOperation) calcColdPress(gt, st, gp float64) float64 {
	const X float64 = 273.0
	const B float64 = 14.504

	coldPress := (st+X)/(gt+X)*(gp+B) - B

	return coldPress / B
}

type ReceiverPositionT struct {
	Rid    string  `json:"rid"`
	Type   int     `json:"type"`
	Plate  string  `json:"plate"`
	Status int     `json:"status"`
	Lat    float32 `json:"lat"`
	Lng    float32 `json:"lng"`
	Lt     int64   `json:"lt"`
	Alert  int     `json:"alert"`
}

type RP struct {
	Lat  float32 `bson:"lat"`
	Lng  float32 `bson:"lng"`
	Latb float32 `bson:"latb"`
	Lngb float32 `bson:"lngb"`
	Latg float32 `bson:"latg"`
	Lngg float32 `bson:"lngg"`
}

type LW struct {
	T    int64 `bson:"t"`
	Warn int   `bson:"warn"`
}

type ReceiverPositionJsonT struct {
	Rid  string `bson:"rid"`
	Type int    `bson:"type"`
	//Plate string `json: "plate"`
	Status int   `bson:"status"`
	Ll     RP    `bson:"ll"`
	Lws    LW    `bson:"lws"`
	Lt     int64 `bson:"lt"`
}

func (p *DBOperation) receiverPositions(cid int, tid string, gpstype string, userid string, page, count, t int) (int, []ReceiverPositionT) {
	s := p.session.Copy()
	defer s.Close()

	var res []ReceiverPositionJsonT
	var total int
	var rids []string
	// var err error

	rets := make([]ReceiverPositionT, 0)
	statuses := []int{1, -1}
	bsonQuery := bson.M{"status": bson.M{"$in": statuses}, "ll": bson.M{"$exists": 1}}
	if cid == 0 && tid == "" {
		userType := p.userType(userid)
		if userType != UserTypeSystemUser {
			rids = p.userReceivers(userid, "")
			if len(rids) == 0 {
				return 0, rets
			}
		}
	} else {
		rids, _ = p.getReceiversOfTeam(cid, tid)
		if len(rids) == 0 {
			return 0, rets
		}
	}
	if len(rids) > 0 {
		bsonQuery["rid"] = bson.M{"$in": rids}
	}
	if t > 0 {
		t = TimeStampToInt(t)
		bsonQuery["ll.t"] = bson.M{"$gt": t}
	}
	c := s.DB(p.dbName).C(CollectionLastStatuses)
	total, _ = c.Find(bsonQuery).Count()
	if total == 0 {
		return 0, nil
	}

	c.Find(bsonQuery).Select(bson.M{"_id": 0, "rid": 1, "type": 1, "status": 1, "ll": 1, "lws": 1, "lt": 1}).
		Skip(count * page).Limit(count).All(&res)

	for _, v := range res {
		if v.Ll.Lat == 0 || v.Ll.Lng == 0 {
			continue
		}
		ret := ReceiverPositionT{}
		ret.Rid = v.Rid
		ret.Type = v.Type
		ret.Status = v.Status
		ret.Lt = v.Lt
		ret.Alert = v.Lws.Warn
		if ret.Status != 0 {
			if time.Now().Unix()-v.Lt > ReceiverOfflineInterval {
				ret.Status = -1
			} else {
				ret.Status = 1
			}
		}
		if gpstype == GpsWGS84 {
			ret.Lat = v.Ll.Lat
			ret.Lng = v.Ll.Lng
		} else if gpstype == GpsGCJ02 {
			ret.Lat = v.Ll.Latg
			ret.Lng = v.Ll.Lngg
		} else {
			ret.Lat = v.Ll.Latb
			ret.Lng = v.Ll.Lngb
		}
		ret.Plate = p.getPlateOnlyByRid(ret.Rid)
		rets = append(rets, ret)
	}

	return total, rets
}

type LastPressureT struct {
	T        int64   `bson:"t" json:"t"`
	Sid      string  `bson:"sid" json:"sid"`
	CardId   int     `bson:"cardid" json:"cardid"`
	SN       int     `bson:"sn" json:"sn"`
	Temp     int     `bson:"temp" json:"temp"`
	Pres     float64 `bson:"pres" json:"pres"`
	ColdPres float64 `json:"coldpres"`
	Vol      float64 `bson:"vol" json:"vol"`
	Warn     string  `json:"warn"`
	Learned  int     `bson:"learned" json:"learned"`
}

type LastWarningT struct {
	T      int64  `bson:"t"`
	Sid    string `bson:"sid"`
	CardId int    `bson:"cardid"`
	SN     int    `bson:"sn"`
	WType  int    `bson:"type"`
	Stat   int    `bson:"stat"`
}

type LastStatusT struct {
	ErrorCode         int     `json:"errcode"`
	Error             string  `json:"error"`
	Rid               string  `bson:"rid" json:"rid"`
	RType             int     `bson:"type" json:"type"`
	Plate             string  `json:"plateno"`
	Frame             string  `json:"frame"`
	ReceiverMileage   float64 `json:"receivermileage"`
	VehicleMileage    float64 `json:"vehiclemileage"`
	Driver            string  `json:"driver"`
	Team              string  `json:"team"`
	Lt                int64   `bson:"lt" json:"lt"`
	Vol               float64 `bson:"vol" json:"vol"`
	GSMSignalStrength int     `bson:"gsm" json:"gsmsignalstrength"`
	GPSSatelliteCount int     `bson:"gpssc" json:"gpssatellitecount"`
	PowerSource       int     `bson:"ps" json:"powersource"`
	LastLocation      struct {
		T      int64   `bson:"t" json:"t"`
		Lat    float64 `bson:"lat" json:"lat"`
		Lng    float64 `bson:"lng" json:"lng"`
		Latb   float64 `bson:"latb" json:"-"`
		Lngb   float64 `bson:"lngb" json:"-"`
		Latg   float64 `bson:"latg" json:"-"`
		Lngg   float64 `bson:"lngg" json:"-"`
		Speed  float64 `bson:"speed" json:"speed"`
		Height int     `bson:"height" json:"height"`
		Dir    int     `bson:"dir" json:"dir"`
	} `bson:"ll" json:"ll"`
	LastPressure []LastPressureT `bson:"lp" json:"lp"`
	LastWarning  []LastWarningT  `bson:"lw" json:"-"`
	Status       int             `bson:"status" json:"status"`
}

func (p *DBOperation) receiverLastStatus(receiverid string, gpstype string) *LastStatusT {
	s := p.session.Copy()
	defer s.Close()

	var res LastStatusT
	c := s.DB(p.dbName).C(CollectionLastStatuses)
	err := c.Find(bson.M{"rid": receiverid}).One(&res)
	if err != nil {
		return &res
	}

	if res.Status != 0 && res.Status != -2 {
		if time.Now().Unix()-res.Lt > ReceiverOfflineInterval {
			res.Status = -1
		} else {
			res.Status = 1
		}
	}

	if gpstype == GpsBd09 {
		res.LastLocation.Lat = res.LastLocation.Latb
		res.LastLocation.Lng = res.LastLocation.Lngb
	} else if gpstype == GpsGCJ02 {
		res.LastLocation.Lat = res.LastLocation.Latg
		res.LastLocation.Lng = res.LastLocation.Lngg
	}

	warn := ""
	for _, v := range res.LastWarning {
		if v.Stat == 0 {
			for i := 0; i < len(res.LastPressure); i++ {
				if v.CardId == res.LastPressure[i].CardId && v.SN == res.LastPressure[i].SN {
					warn = res.LastPressure[i].Warn
					if warn == "" {
						warn = strconv.Itoa(v.WType)
					} else {
						warn += warn + "," + strconv.Itoa(v.WType)
					}
					res.LastPressure[i].Warn = warn
				}
			}
		}
	}

	return &res
}

type TeamAndPlateNoT struct {
	Cid         int     `bson:"cid"`
	Tid         string  `bson:"tid"`
	Driver      string  `bson:"driver"`
	DriverPhone string  `bson:"driverphone"`
	Plate       string  `bson:"plate"`
	Frame       string  `bson:"frame"`
	Ma          float32 `bson:"ma"`
}

func (p *DBOperation) receiverTeamAndPlateNo(rid string) (team string, driver string, plateNo string, frameNo string, rma float64, vma float32) {
	type VidMaT struct {
		Vid string  `bson:"vid"`
		Ma  float64 `bson:"ma"`
	}

	s := p.session.Copy()
	defer s.Close()

	var res VidMaT
	c := s.DB(p.dbName).C(CollectionReceivers)
	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "vid": 1, "ma": 1}).One(&res)
	if err != nil {
		return
	}

	rma = res.Ma
	cardId := res.Vid
	// }
	if cardId == "" || !bson.IsObjectIdHex(cardId) {
		return
	}

	var tp TeamAndPlateNoT
	c = s.DB(p.dbName).C(CollectionVehicles)
	err = c.Find(bson.M{"vid": cardId}).Select(bson.M{"_id": 0, "cid": 1, "tid": 1, "driver": 1, "driverphone": 1, "plate": 1, "frame": 1, "ma": 1}).One(&tp)
	if err != nil {
		return
	}
	plateNo = tp.Plate
	driver = p.getVehicleDriver(cardId)
	if driver == "" {
		if tp.DriverPhone != "" {
			driver = tp.Driver + "(" + tp.DriverPhone + ")"
		} else {
			driver = tp.Driver
		}
	}

	frameNo = tp.Frame
	vma = tp.Ma
	team = p.getTeamName(tp.Tid)

	return
}

type VehicleDriverT struct {
	Name  string `bson:"name"`
	Phone string `bson:"phone"`
}

func (p *DBOperation) getVehicleDriver(vid string) string {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicles)
	var dids struct {
		Dids []string `bson:"dids"`
	}
	err := c.Find(bson.M{"vid": vid}).Select(bson.M{"_id": 0, "dids": 1}).One(&dids)
	if err != nil || len(dids.Dids) == 0 {
		return ""
	}

	c = s.DB(p.dbName).C(CollectionDrivers)
	var drivers []VehicleDriverT
	err = c.Find(bson.M{"did": bson.M{"$in": dids.Dids}}).Select((bson.M{"name": 1, "phone": 1, "_id": 0})).All(&drivers)
	if err != nil {
		return ""
	}

	var sDrivers string
	for _, v := range drivers {
		sDrivers += v.Name + "(" + v.Phone + "),"
	}
	if len(sDrivers) > 1 {
		sDrivers = sDrivers[:len(sDrivers)-1]
	}
	return sDrivers
}

func (p *DBOperation) getCompanyName(cid int) string {
	s := p.session.Copy()
	defer s.Close()

	var res map[string]string
	c := s.DB(p.dbName).C(CollectionCompanies)
	err := c.Find(bson.M{"cid": cid}).Select(bson.M{"_id": 0, "name": 1}).One(&res)
	if err != nil {
		return ""
	}
	return res["name"]
}

func (p *DBOperation) getTeamName(tid string) string {
	s := p.session.Copy()
	defer s.Close()

	var res map[string]string
	c := s.DB(p.dbName).C(CollectionTeams)
	err := c.Find(bson.M{"tid": tid}).Select(bson.M{"name": 1, "_id": 0}).One(&res)
	if err != nil {
		return ""
	}
	return res["name"]
}

func (p *DBOperation) getTeamCidAndName(tid string) (int, string) {
	s := p.session.Copy()
	defer s.Close()

	var res struct {
		Cid  int    `bson:"cid"`
		Name string `bson:"name"`
	}
	c := s.DB(p.dbName).C(CollectionTeams)
	err := c.Find(bson.M{"tid": tid}).Select(bson.M{"cid": 1, "name": 1, "_id": 0}).One(&res)
	if err != nil {
		return 0, ""
	}
	return res.Cid, res.Name
}

func (p *DBOperation) getWarehouseName(wid int64) string {
	s := p.session.Copy()
	defer s.Close()

	var res map[string]string
	c := s.DB(p.dbName).C(CollectionWarehouses)
	err := c.Find(bson.M{"wid": wid}).Select(bson.M{"_id": 0, "name": 1}).One(&res)
	if err != nil {
		return ""
	}

	return res["name"]
}

func (p *DBOperation) getWarehouseID(cid int, tid string, name string) int64 {
	if name == "" {
		return 0
	}

	s := p.session.Copy()
	defer s.Close()

	var res map[string]int64
	c := s.DB(p.dbName).C(CollectionWarehouses)
	bsonQuery := bson.M{"cid": cid}
	if tid != "" {
		bsonQuery["tid"] = tid
	}
	bsonQuery["name"] = name
	err := c.Find(bsonQuery).Select(bson.M{"wid": 1}).One(&res)
	if err != nil {
		return 0
	}

	return res["wid"]
}

func (p *DBOperation) getWarehouseByTire(cid int, tno string) (int, string) {
	s := p.session.Copy()
	defer s.Close()

	var res map[string]int
	c := s.DB(p.dbName).C(CollectionTires)
	err := c.Find(bson.M{"cid": cid, "tno": tno}).Select(bson.M{"_id": 0, "wid": 1}).One(&res)
	if err != nil {
		return 0, ""
	}

	wid := res["wid"]
	if wid == 0 {
		return 0, ""
	}

	return wid, p.getWarehouseName(int64(wid))
}

type LocationDBT struct {
	Time      int     `bson:"time" json:"time"`
	Lat       float64 `bson:"lat" json:"lat"`
	Lng       float64 `bson:"lng" json:"lng"`
	LatB      float64 `bson:"latf" json:"-"`
	LngB      float64 `bson:"lngf" json:"-"`
	LatG      float64 `bson:"latg" json:"-"`
	LngG      float64 `bson:"lngg" json:"-"`
	Speed     float64 `bson:"speed" json:"speed"`
	Height    int     `bson:"height" json:"height"`
	Direction int     `bson:"dir" json:"dir"`
}

type LocationT struct {
	Time      int     `json:"time"`
	Lat       float64 `json:"lat"`
	Lng       float64 `json:"lng"`
	Speed     float64 `json:"speed"`
	Height    int     `json:"height"`
	Direction int     `json:"dir"`
}

func (p *DBOperation) receiverTrack(receiverid string, date int, gpstype string) []LocationT {
	s := p.session.Copy()
	defer s.Close()

	var res []LocationDBT
	c := s.DB(p.dbName).C(CollectionPositions)

	err := c.Find(bson.M{"rid": receiverid, "date": date}).
		Select(bson.M{"_id": 0, "time": 1, "lat": 1, "lng": 1, "latf": 1, "lngf": 1, "latg": 1, "lngg": 1, "speed": 1, "dir": 1, "height": 1}).
		Sort("time").
		All(&res)
	if err != nil {
		return nil
	}

	locs := make([]LocationT, 0)
	var loc *LocationDBT
	lastLat := 0.0
	lastLng := 0.0

	for i := 0; i < len(res); i++ {
		loc = &res[i]
		if loc.Lat != lastLat || loc.Lng != lastLng {
			lastLat, lastLng = loc.Lat, loc.Lng

			lt := LocationT{Time: loc.Time, Speed: loc.Speed, Height: loc.Height, Direction: loc.Direction}

			if gpstype == GpsBd09 {
				lt.Lat, lt.Lng = loc.LatB, loc.LngB
			} else if gpstype == GpsGCJ02 {
				lt.Lat, lt.Lng = loc.LatG, loc.LngG
			} else {
				lt.Lat, lt.Lng = loc.Lat, loc.Lng
			}

			locs = append(locs, lt)
		}
	}

	return locs
}

func (p *DBOperation) receiverMileage(rid string, date int) float64 {
	s := p.session.Copy()
	defer s.Close()

	y := date / 10000
	m := date % 10000 / 100
	d := date % 100

	var res map[string]float64

	c := s.DB(p.dbName).C(CollectionMileageStatistics)
	err := c.Find(bson.M{"rid": rid, "y": y, "m": m, "d": d}).Select(bson.M{"_id": 0, "ma": 1}).One(&res)
	if err != nil {
		return 0.0
	}

	return res["ma"]
}

func (p *DBOperation) receiverTireDataHistory(receiverid string, date int) []map[string]interface{} {
	s := p.session.Copy()
	defer s.Close()

	var res []map[string]interface{}
	c := s.DB(p.dbName).C(CollectionTireRawDatas)
	c.Find(bson.M{"rid": receiverid, "date": date}).Select(bson.M{"_id": 0, "rawid": 0, "rid": 0, "date": 0, "lat": 0, "lng": 0, "tires.epdins": 0, "tires.epdlos": 0}).
		Sort("time").
		All(&res)
	return res
}

func (p *DBOperation) sensorDataHistory(sensorid string, date int) []map[string]interface{} {
	s := p.session.Copy()
	defer s.Close()

	var res []map[string]interface{}
	c := s.DB(p.dbName).C(CollectionTireDatas)
	c.Find(bson.M{"sid": sensorid, "date": date}).Select(bson.M{"_id": 0, "time": 1, "pres": 1, "temp": 1}).
		Sort("time").
		All(&res)
	return res
}

type TireDataT struct {
	T    int     `bson:"time" json:"time"`
	Pres float64 `bson:"pres" json:"pres"`
	Temp int     `bson:"temp" json:"temp"`
}

func (p *DBOperation) sensorDataHistory2(receiver string, cardid int, sn int, date int) []TireDataT { //map[string]interface{} {
	s := p.session.Copy()
	defer s.Close()

	var res []TireDataT
	c := s.DB(p.dbName).C(CollectionTireDatas)
	needFix := false

	if receiver == "060422111724" {
		if cardid == 1 {
			if sn == 2 || sn == 6 || sn == 10 {
				sn--
				needFix = true
			} else if sn == 3 || sn == 7 || sn == 11 {
				sn++
				needFix = true
			}
		}
	}

	c.Find(bson.M{"rid": receiver, "cardid": cardid, "sn": sn, "date": date}).Select(bson.M{"_id": 0, "time": 1, "pres": 1, "temp": 1}).
		Sort("time").
		All(&res)

	if needFix {
		for i := 0; i < len(res); i++ {
			res[i].Temp = res[i].Temp - 3
		}
	}
	return res
}

type TireRelationT struct {
	Tno    string `bson:"tno"`
	CardId int    `bson:"cardid"`
	Sn     int    `bson:"sn"`
}

func (p *DBOperation) tireInfo(rid, sid string) (*TireInfoT, error) {
	s := p.session.Copy()
	defer s.Close()

	var tl TireRelationT
	var tireInfo TireInfoT

	c := s.DB(p.dbName).C(CollectionRelations)
	err := c.Find(bson.M{"rid": rid, "sid": sid}).Select(bson.M{"_id": 0, "tno": 1, "cardid": 1, "sn": 1}).One(&tl)
	if err != nil {
		return nil, err
	}

	tireInfo.CardId = tl.CardId
	tireInfo.Sn = tl.Sn
	tireInfo.TireNo = tl.Tno
	cid, _ := p.getCompanyAndTeamByRid(rid)
	p.getTireInfo(cid, tl.Tno, &tireInfo)

	return &tireInfo, nil
}

func (p *DBOperation) vehicleTire(vid string, cardid, sn int) *TireInfoT {
	s := p.session.Copy()
	defer s.Close()

	var tl TireRelationT
	var tireInfo TireInfoT

	c := s.DB(p.dbName).C(CollectionRelations)
	err := c.Find(bson.M{"vid": vid, "cardid": cardid, "sn": sn}).Select(bson.M{"_id": 0, "tno": 1}).One(&tl)
	if err != nil {
		tireInfo.CardId = cardid
		tireInfo.Sn = sn
		return &tireInfo
	}

	tireInfo.CardId = cardid
	tireInfo.Sn = sn
	tireInfo.TireNo = tl.Tno
	cid, _ := p.getCompanyAndTeamByVid(vid)
	p.getTireInfo(cid, tl.Tno, &tireInfo)

	return &tireInfo
}

func (p *DBOperation) queryReceiverId(rid string) []string {
	s := p.session.Copy()
	defer s.Close()

	result := make([]string, 0)
	var res []map[string]string

	c := s.DB(p.dbName).C(CollectionReceivers)
	bsonReg := bson.RegEx{Pattern: rid, Options: "im"}
	err := c.Find(bson.M{"rid": bsonReg}).Select(bson.M{"_id": 0, "rid": 1}).Limit(10).All(&res)
	if err == nil {
		for _, v := range res {
			result = append(result, v["rid"])
		}
	}

	return result
}

type TireInfoDBT struct {
	BrandID     int       `bson:"bid"`
	Mid         string    `bson:"mid"`
	Pattern     string    `bson:"pattern"`
	Dot         string    `bson:"dot"`
	RFID        string    `bson:"rfid"`
	Ma          float32   `bson:"ma"`
	Cpdepths    []float32 `bson:"cpdepths"`
	Operator    string    `bson:"operator"`
	OperateTime int       `bson:"ot"`
	Status      int       `bson:"status"`
}

func (p *DBOperation) getTireInfo(cid int, tno string, tireInfo *TireInfoT) {
	s := p.session.Copy()
	defer s.Close()

	var tidb TireInfoDBT
	c := s.DB(p.dbName).C(CollectionTires)
	err := c.Find(bson.M{"cid": cid, "tno": tno}).Select(bson.M{"_id": 0, "bid": 1, "mid": 1, "pattern": 1, "dot": 1,
		"rfid": 1, "ma": 1, "cpdepths": 1, "operator": 1, "ot": 1, "status": 1}).
		One(&tidb)
	if err != nil {
		return
	}

	tireInfo.Mileage = tidb.Ma
	tireInfo.Depth = tidb.Cpdepths
	if tireInfo.Depth == nil {
		tireInfo.Depth = make([]float32, 0)
	}
	tireInfo.Model = tidb.Mid
	tireInfo.Pattern = tidb.Pattern
	tireInfo.Dot = tidb.Dot
	tireInfo.RFID = tidb.RFID
	tireInfo.BrandID = tidb.BrandID
	tireInfo.Brand = p.getTireBrandByMid(tidb.BrandID, tidb.Mid)
	tireInfo.Operator = tidb.Operator
	tireInfo.OperateTime = tidb.OperateTime
	tireInfo.Status = tidb.Status
}

func (p *DBOperation) getTireBrandByMid(brandid int, model string) string {
	s := p.session.Copy()
	defer s.Close()

	var tbid int
	var err error

	c := s.DB(p.dbName).C(CollectionTireModels)
	if brandid == 0 {
		var res map[string]int
		err = c.Find(bson.M{"tmid": model}).Select(bson.M{"_id": 0, "tbid": 1}).One(&res)
		if err != nil {
			return ""
		}
		tbid = res["tbid"]
	} else {
		tbid = brandid
	}

	var resName map[string]string
	c = s.DB(p.dbName).C(CollectionTireBrands)
	err = c.Find(bson.M{"tbid": tbid}).Select(bson.M{"name": 1, "_id": 0}).One(&resName)
	if err != nil {
		return ""
	}
	name := resName["name"]
	return name
}

func (p *DBOperation) getTireBrandName(cid, bid int) string {
	s := p.session.Copy()
	defer s.Close()

	var res map[string]string
	c := s.DB(p.dbName).C(CollectionTireBrands)
	bsonQuery := bson.M{"tbid": bid}
	if cid != 0 {
		bsonQuery["cid"] = cid
	}
	err := c.Find(bsonQuery).Select(bson.M{"name": 1}).One(&res)
	if err != nil {
		return ""
	}
	return res["name"]
}

func (p *DBOperation) getTireBrandIdByName(cid int, brand string) int {
	s := p.session.Copy()
	defer s.Close()

	var res map[string]int
	c := s.DB(p.dbName).C(CollectionTireBrands)
	bsonQuery := bson.M{"name": brand}
	if cid != 0 {
		bsonQuery["cid"] = cid
	}
	err := c.Find(bsonQuery).Select(bson.M{"tbid": 1}).One(&res)
	if err != nil {
		return 0
	}
	return res["tbid"]
}

func (p *DBOperation) teamListByTid(tid string, needcid int) []map[string]interface{} {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTeams)
	res := []map[string]interface{}{}
	bsonSelect := bson.M{"_id": 0, "name": 1 /* "cid": 1, */, "tid": 1}
	if needcid == 1 {
		bsonSelect["cid"] = 1
	}
	err := c.Find(bson.M{"pid": tid}).Select(bsonSelect).Sort("name").All(&res)
	if err != nil {
		return make([]map[string]interface{}, 0)
	}

	var pTeam *map[string]interface{}
	var tempTid string
	var tempTeams []map[string]interface{}

	for i := 0; i < len(res); i++ {
		pTeam = &res[i]
		tempTid = (*pTeam)["tid"].(string)
		tempTeams = p.teamListByTid(tempTid, needcid)
		(*pTeam)["teams"] = tempTeams
	}

	return res
}

func (p *DBOperation) teamListByCid(cid int, needcid int) []map[string]interface{} {
	s := p.session.Copy()
	defer s.Close()

	res := []map[string]interface{}{}
	c := s.DB(p.dbName).C(CollectionTeams)
	bsonQuery := bson.M{"cid": cid, "pid": ""}

	bsonSelect := bson.M{"_id": 0 /*"cid": 1, */, "tid": 1, "name": 1}
	if needcid == 1 {
		bsonSelect["cid"] = 1
	}
	err := c.Find(bsonQuery).Select(bsonSelect).Sort("name").All(&res)
	if err != nil {
		return make([]map[string]interface{}, 0)
	}

	var pTeam *map[string]interface{}
	var tempTid string
	var tempTeams []map[string]interface{}

	for i := 0; i < len(res); i++ {
		pTeam = &res[i]
		tempTid = (*pTeam)["tid"].(string)
		tempTeams = p.teamListByTid(tempTid, needcid)
		(*pTeam)["teams"] = tempTeams
	}

	return res
}

func (p *DBOperation) addTeam(cid int, pid string, name, contact, phone, workflow string) (tid string, err error) {
	s := p.session.Copy()
	defer s.Close()

	query := bson.M{"cid": cid, "name": name}
	if pid != "" {
		query["pid"] = pid
	}

	c := s.DB(p.dbName).C(CollectionTeams)
	err = c.Find(query).Select(bson.M{"_id": 1}).One(nil)
	if err == nil {
		err = errors.New("已经存在相同的车队名。")
		return
	}

	newRecord := bson.M{}
	_id := bson.NewObjectId()
	tid = _id.Hex()
	newRecord["_id"] = _id
	newRecord["cid"] = cid
	newRecord["tid"] = tid
	newRecord["pid"] = pid
	newRecord["name"] = name
	newRecord["manager"] = contact
	newRecord["phone"] = phone
	newRecord["workflow"] = workflow
	err = c.Insert(newRecord)

	return
}

func (p *DBOperation) editTeam(tid, name, contact, phone, workflow string) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTeams)
	return c.Update(bson.M{"tid": tid}, bson.M{"$set": bson.M{"name": name, "manager": contact, "phone": phone,
		"workflow": workflow}})
}

func (p *DBOperation) deleteTeam(tid string) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTeams)
	var res map[string]interface{}

	err := c.Find(bson.M{"tid": tid}).One(&res)
	if err == nil {
		c.Remove(bson.M{"tid": tid})
	}
}

func (p *DBOperation) vehicleBrandList(cid int) []map[string]string {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicleBrands)
	var res []map[string]string
	bsonQuery := bson.M{}
	if cid != 0 {
		bsonQuery["cid"] = cid
	}
	bsonQuery["vmid"] = bson.M{"$exists": false}

	err := c.Find(bsonQuery).Select(bson.M{"_id": 0, "vbid": 1, "name": 1}).All(&res)
	if err != nil {
		return make([]map[string]string, 0)
	}
	return res
}

func (p *DBOperation) vehicleBrandAdd(cid int, name string) (string, error) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicleBrands)

	err := c.Find(bson.M{"cid": cid, "name": name}).One(nil)
	if err == nil {
		err = errors.New("brand name alreay exists")
		return "", err
	}

	id := bson.NewObjectId()
	err = c.Insert(bson.M{"vbid": id.Hex(), "cid": cid, "name": name})
	return id.Hex(), err
}

func (p *DBOperation) vehicleBrandEdit(id, name string) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicleBrands)

	err := c.Find(bson.M{"name": name}).Select(bson.M{"_id": 1}).One(nil)
	if err == nil {
		return errors.New("brand name alreay exists")
	}

	_, err = c.UpdateAll(bson.M{"vbid": id}, bson.M{"$set": bson.M{"name": name}})
	return err
}

func (p *DBOperation) vehicleBrandDelete(id string) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicleBrands)
	_, err := c.RemoveAll(bson.M{"vbid": id})
	return err
}

func (p *DBOperation) vehicleModelList(vbid string) []map[string]string {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicleBrands)
	var res []map[string]string

	err := c.Find(bson.M{"vbid": vbid, "vmid": bson.M{"$exists": true}}).Select(bson.M{"_id": 0, "vmid": 1, "vmname": 1}).All(&res)
	if err != nil || res == nil {
		return make([]map[string]string, 0)
	}
	return res
}

func (p *DBOperation) vehicleModelAdd(vbid, name, model string) (string, error) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicleBrands)

	err := c.Find(bson.M{"vbid": vbid, "vmname": model}).One(nil)
	if err == nil {
		err = errors.New("model already exists")
		return "", err
	}

	id := bson.NewObjectId()
	err = c.Insert(bson.M{"vbid": vbid, "name": name, "vmid": id.Hex(), "vmname": model})
	return id.Hex(), err
}

func (p *DBOperation) vehicleModelEdit(vbid, vmid, name string) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicleBrands)

	err := c.Find(bson.M{"vbid": vbid, "vmname": name}).Select(bson.M{"_id": 1}).One(nil)
	if err == nil {
		return errors.New("model already exists")
	}

	err = c.Update(bson.M{"vmid": vmid}, bson.M{"$set": bson.M{"vmname": name}})
	return err
}

func (p *DBOperation) vehicleModelDelete(id string) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicleBrands)
	err := c.Remove(bson.M{"vmid": id})
	return err
}

type VehicleDBT struct {
	Vid         string   `bson:"vid" json:"vid"`
	Cid         int      `bson:"cid" json:"cid"`
	Tid         string   `bson:"tid" json:"tid"`
	TName       string   `json:"teamname"`
	Dids        []string `bson:"dids" json:"-"`
	Driver      string   `bson:"driver" json:"driver"`
	DriverPhone string   `bson:"driverphone" json:"driverphone"`
	Plate       string   `bson:"plate" json:"plate"`
	Frame       string   `bson:"frame" json:"frame"`
	Type        int      `bson:"type" json:"type"`
	Rid         string   `bson:"rid" json:"rid"`
	EngineType  int      `bson:"enginetype" json:"enginetype"`
}

func (p *DBOperation) vehicleList(cid int, tid string, content string, page int) (int, []VehicleDBT) {
	s := p.session.Copy()
	defer s.Close()

	var c *mgo.Collection
	var ret []VehicleDBT
	var vids []string
	var err error

	c = s.DB(p.dbName).C(CollectionVehicles)

	bsonQuery := bson.M{}
	if cid != 0 {
		bsonQuery["cid"] = cid
	}
	if tid != "" {
		bsonQuery["tids"] = tid
	}
	if content != "" {
		bsonOR := []bson.M{
			{"plate": bson.RegEx{Pattern: content, Options: "im"}},
			{"frame": bson.RegEx{Pattern: content, Options: "im"}},
			{"rid": bson.RegEx{Pattern: content, Options: "im"}}}
		bsonQuery["$or"] = bsonOR
	}

	total, _ := c.Find(bsonQuery).Count()
	if total == 0 {
		return 0, make([]VehicleDBT, 0)
	}

	err = c.Find(bsonQuery).Select(bson.M{"_id": 1, "vid": 1, "cid": 1, "tid": 1, "rid": 1, "type": 1, "driver": 1, "driverphone": 1,
		"dids": 1, "plate": 1, "frame": 1, "enginetype": 1}).All(&ret)

	if err == nil {
		vidMap := p.getRidOfVid(vids)

		for i := 0; i < len(ret); i++ {
			if ret[i].Tid != "" {
				ret[i].TName = p.getTeamName(ret[i].Tid)
			} else {
				ret[i].TName = p.getCompanyName(ret[i].Cid)
			}
			if ret[i].Rid == "" {
				ret[i].Rid = vidMap[ret[i].Vid]
			}
			if ret[i].Driver == "" {
				ret[i].Driver, ret[i].DriverPhone = p.getDriversInfo(ret[i].Dids)
			}
		}
	}

	return total, ret
}

func (p *DBOperation) getRidOfVid(vids []string) (ret map[string]string) {
	s := p.session.Copy()
	defer s.Close()

	ret = make(map[string]string)
	var res []map[string]string

	c := s.DB(p.dbName).C(CollectionReceivers)
	err := c.Find(bson.M{"vid": bson.M{"$in": vids}}).Select(bson.M{"_id": 0, "rid": 1, "vid": 1}).All(&res)
	if err == nil {
		var rid, vid string
		for _, v := range res {
			rid = v["rid"]
			vid = v["vid"]
			ret[vid] = rid
		}
	}

	return
}

func (p *DBOperation) getDriversInfo(dids []string) (names, phones string) {
	if len(dids) == 0 {
		return
	}

	s := p.session.Copy()
	defer s.Close()

	var res []map[string]string
	c := s.DB(p.dbName).C(CollectionDrivers)
	err := c.Find(bson.M{"did": bson.M{"$in": dids}}).Select(bson.M{"name": 1, "phone": 1, "_id": 0}).All(&res)
	if err == nil {
		for _, v := range res {
			names += v["name"] + ","
			phones += v["phone"] + ","
		}

		tLen := len(names)
		if tLen > 0 {
			names = names[:tLen-1]
		}
		tLen = len(phones)
		if tLen > 0 {
			phones = phones[:tLen-1]
		}
	}
	return
}

type VehicleT struct {
	Vid         string              `bson:"vid" json:"vid"`
	Cid         int                 `bson:"cid" json:"cid"`
	Tid         string              `bson:"tid" json:"tid"`
	TName       string              `json:"teamname"`
	DriverIds   []string            `bson:"dids" json:"-"`
	Driver      string              `bson:"driver" json:"-"`
	DriverPhone string              `bson:"driverphone" json:"-"`
	Drivers     []map[string]string `json:"drivers"`
	Plate       string              `bson:"plate" json:"plate"`
	Frame       string              `bson:"frame" json:"frame"`
	Type        int                 `bson:"type" json:"type"`
	Rid         string              `bson:"rid" json:"rid"`
	EngineType  int                 `bson:"enginetype" json:"enginetype"`
	InstallDate int64               `bson:"dop" json:"it"`
	LastTime    int64               `json:"lt"`
}

func (p *DBOperation) vehicleList2(userid string, cid int, tid string, content, sort string, page int) (int, []VehicleT) {
	s := p.session.Copy()
	defer s.Close()
	const PageSize int = 10

	var ret []VehicleT

	c := s.DB(p.dbName).C(CollectionVehicles)
	bsonQuery := bson.M{}

	if tid != "" {
		bsonQuery["tids"] = tid
	} else {
		if cid != 0 {
			bsonQuery["cid"] = cid
		}
	}

	if content != "" {
		bsonOR := []bson.M{
			{"plate": bson.RegEx{Pattern: content, Options: "im"}},
			{"frame": bson.RegEx{Pattern: content, Options: "im"}},
			{"rid": bson.RegEx{Pattern: content, Options: "im"}}}
		bsonQuery["$or"] = bsonOR
	}

	total, _ := c.Find(bsonQuery).Count()
	if total == 0 {
		return 0, make([]VehicleT, 0)
	}

	q := c.Find(bsonQuery).Select(bson.M{"_id": 1, "vid": 1, "cid": 1, "tid": 1, "rid": 1, "type": 1, "driver": 1, "driverphone": 1,
		"plate": 1, "frame": 1, "dids": 1, "enginetype": 1, "dop": 1})
	if sort != "" {
		q.Sort(sort)
	}
	q.Skip(page * PageSize).Limit(PageSize).All(&ret)

	for i := 0; i < len(ret); i++ {
		if ret[i].Tid != "" {
			ret[i].TName = p.getTeamName(ret[i].Tid)
		} else {
			ret[i].TName = p.getCompanyName(ret[i].Cid)
		}
		if ret[i].Rid != "" {
			ret[i].LastTime = p.getRidLastTime(ret[i].Rid)
		}
		if ret[i].DriverIds != nil && len(ret[i].DriverIds) > 0 {
			ret[i].Drivers = p.getDriverById(ret[i].DriverIds)
		} else if ret[i].Driver != "" {
			ret[i].Drivers = make([]map[string]string, 0)
			ret[i].Drivers = append(ret[i].Drivers, map[string]string{"did": "", "name": ret[i].Driver, "phone": ret[i].DriverPhone})
		}
	}

	return total, ret
}

type PropertyT struct {
	Cid   int    `json:"cid" bson:"cid"`
	Tid   string `json:"tid" bson:"tid"`
	Rid   string `json:"rid" bson:"rid"`
	Vid   string `json:"vid" bson:"vid"`
	Plate string `json:"plate" bson:"plate"`
	Type  int    `json:"type" bson:"type"`
}

func (p *DBOperation) propreties(cid int, tid, key string) []PropertyT {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicles)
	var res, res2 []PropertyT

	bsonQuery := bson.M{}
	if cid != 0 {
		bsonQuery["cid"] = cid
	}
	if tid != "" {
		bsonQuery["tids"] = tid
	}
	if key != "" {
		bsonOR := []bson.M{
			{"plate": bson.RegEx{Pattern: key, Options: "im"}},
			{"frame": bson.RegEx{Pattern: key, Options: "im"}},
			{"rid": bson.RegEx{Pattern: key, Options: "im"}}}
		bsonQuery["$or"] = bsonOR
	}

	c.Find(bsonQuery).Select(bson.M{"_id": 0, "cid": 1, "tid": 1, "rid": 1, "vid": 1, "plate": 1, "frame": 1, "type": 1}).
		Limit(10).All(&res)

	resLen := len(res)

	if resLen == 10 {
		return res
	}

	c = s.DB(p.dbName).C(CollectionReceivers)
	bsonQuery = bson.M{}
	if cid != 0 {
		bsonQuery["cid"] = cid
	}
	if tid != "" {
		bsonQuery["tids"] = tid
	}
	if key != "" {
		bsonQuery["rid"] = bson.RegEx{Pattern: key, Options: "im"}
	}
	err := c.Find(bsonQuery).Select(bson.M{"_id": 0, "cid": 1, "tid": 1, "rid": 1, "type": 1}).Limit(10).All(&res2)
	if err == nil {
		bFound := false
		for _, v := range res2 {
			if len(res) >= 10 {
				break
			}

			bFound = false
			for _, vv := range res {
				if v.Rid == vv.Rid {
					bFound = true
					break
				}
			}
			if !bFound {
				res = append(res, v)
			}
		}
	}

	return res
}

func (p *DBOperation) getRidLastTime(rid string) int64 {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionLastStatuses)
	var res map[string]int64
	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "lt": 1}).One(&res)
	if err != nil {
		return 0
	}
	return res["lt"]
}

func (p *DBOperation) getDriverById(ids []string) []map[string]string {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionDrivers)
	var res []map[string]string
	c.Find(bson.M{"did": bson.M{"$in": ids}}).Select(bson.M{"_id": 0, "did": 1, "name": 1, "phone": 1}).All(&res)
	return res
}

func (p *DBOperation) vehicleEdit2(v *VehicleInfoDBT) error {
	//根据VID读入原来的数据
	var oldV VehicleDBT
	var err error

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicles)
	err = c.Find(bson.M{"vid": v.Vid}).Select(bson.M{"_id": 0, "tid": 1, "type": 1, "rid": 1}).One(&oldV)
	if err == nil {
		//首先，修改车辆表中的数据
		err = c.Update(bson.M{"vid": v.Vid}, bson.M{"$set": bson.M{"tid": v.Tid, "tids": v.Tids, "rid": v.Rid, "dids": v.DriverIDs,
			"vbid": v.BrandID, "vmid": v.ModelID, "dom": v.Dom, "dop": v.Dop, "sp": v.Payload, "rp": v.RealPayload,
			"plate": v.Plate, "type": v.Type, "frame": v.Frame, "ima": v.InitMileage, "enginetype": v.EngineType}})
		if err == nil {
			if v.Rid != "" {
				p.setReceiverType(v.Rid, v.Type)
			}

			if v.Tid != oldV.Tid {
				c = s.DB(p.dbName).C(CollectionOrganizationProperties)
				if oldV.Tid != "" {
					c.RemoveAll(bson.M{"vid": v.Vid, "tid": bson.M{"$exists": 1}})
				}
				if oldV.Rid != "" {
					c.RemoveAll(bson.M{"rid": oldV.Rid, "tid": bson.M{"$exists": 1}})
					p.removeReceiverFromTeam(oldV.Tid, oldV.Rid)
				}

				if v.Tid != "" {
					tids := p.getTeamParents(v.Tid)
					for _, tid := range tids {
						p.addVehicleToTeam(tid, v.Vid)

						if v.Rid != "" {
							p.addReceiverToTeam(tid, v.Rid)
						}
					}
				}
			}
			c = s.DB(p.dbName).C(CollectionReceivers)

			if oldV.Rid != v.Rid {
				if oldV.Rid != "" {
					c.Update(bson.M{"rid": oldV.Rid}, bson.M{"$set": bson.M{"vid": ""}})
				}
				if v.Rid != "" {
					c.Update(bson.M{"rid": v.Rid}, bson.M{"$set": bson.M{"vid": v.Vid}})
				}
			}
			if oldV.Plate != v.Plate {
				c.Update(bson.M{"rid": v.Rid}, bson.M{"$set": bson.M{"plate": v.Plate}})
				if oldV.Rid != v.Rid && oldV.Rid != "" {
					c.Update(bson.M{"rid": oldV.Rid}, bson.M{"$set": bson.M{"plate": ""}})
				}
			}
		}
	}

	return err
}

func (p *DBOperation) vehicleRemove(vid string) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicles)
	c.Remove(bson.M{"vid": vid})

	c = s.DB(p.dbName).C(CollectionOrganizationProperties)
	c.RemoveAll(bson.M{"vid": vid})

	var res map[string]interface{}
	var oid bson.ObjectId

	c = s.DB(p.dbName).C(CollectionReceivers)
	err := c.Find(bson.M{"vid": vid}).Select(bson.M{"_id": 1, "rid": 1}).One(&res)
	if err == nil {
		oid = res["_id"].(bson.ObjectId)
		c.Update(bson.M{"_id": oid}, bson.M{"$set": bson.M{"vid": ""}})
	}
}

type DriverBriefInfoT struct {
	DriverId string `bson:"did" json:"id"`
	Name     string `bson:"name" json:"name"`
	Phone    string `bson:"phone" json:"phone"`
}

type VehicleInfoT struct {
	Vid         string             `bson:"vid" json:"vid"`
	BrandID     string             `bson:"vbid" json:"brandid"`
	Brand       string             `json:"brand"`
	ModelID     string             `bson:"vmid" json:"modelid"`
	Model       string             `json:"model"`
	Dom         int                `bson:"dom" json:"dom"`
	Dop         int                `bson:"dop" json:"dop"`
	Payload     int                `bson:"sp" json:"payload"`
	RealPayload int                `bson:"rp" json:"realpayload"`
	Cid         int                `bson:"cid" json:"cid"`
	Tid         string             `bson:"tid" json:"tid"`
	TName       string             `json:"teamname"`
	DriverIDs   []string           `bson:"dids" json:"-"`
	Drivers     []DriverBriefInfoT `json:"drivers"`
	Plate       string             `bson:"plate" json:"plate"`
	Frame       string             `bson:"frame" json:"frame"`
	Type        int                `bson:"type" json:"type"`
	Rid         string             `bson:"rid" json:"rid"`
	EngineType  int                `bson:"enginetype" json:"enginetype"`
	Ima         float32            `bson:"ima" json:"initmileage"`
	Ma          float32            `bson:"ma" json:"ma"`
}

func (p *DBOperation) vehicleInfo(vid string) (*VehicleInfoT, error) {

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicles)
	var v VehicleInfoT

	err := c.Find(bson.M{"vid": vid}).One(&v)
	if err != nil {
		return nil, err
	}

	if v.Tid != "" {
		v.TName = p.getTeamName(v.Tid)
	} else {
		v.TName = p.getCompanyName(v.Cid)
	}
	v.Drivers = make([]DriverBriefInfoT, 0)
	for _, driverId := range v.DriverIDs {
		dbi := p.driverBriefInfo(driverId)
		if dbi != nil {
			v.Drivers = append(v.Drivers, *dbi)
		}
	}
	if v.BrandID != "" {
		v.Brand, v.Model = p.getVehicleBrandAndModel(v.BrandID, v.ModelID)
	}
	if v.Rid == "" {
		v.Rid = p.getRidByVid(vid)
	}
	return &v, nil
}

type VehicleTireInfoT struct {
	SN          int     `json:"sn"`
	SID         string  `json:"sid"`
	TireNO      string  `json:"tno" bson:"tno"`
	Temperature int     `json:"temp"`
	Pressure    float32 `json:"pres"`
	Volume      float32 `json:"vol"`
	Warn        string  `json:"warn"`
	CardID      int     `json:"-"`
	Active      bool    `json:"active"`
	T           int     `json:"t"`
}

type VehicleTireDatasT struct {
	CardID int                 `json:"cardid"`
	Tires  []*VehicleTireInfoT `json:"tires"`
}

func (p *VehicleTireDatasT) find(sn int) *VehicleTireInfoT {
	for i := 0; i < len(p.Tires); i++ {
		if p.Tires[i].SN == sn {
			return p.Tires[i]
		}
	}
	vti := VehicleTireInfoT{SN: sn}
	p.Tires = append(p.Tires, &vti)
	return &vti
}

func (p *VehicleTireDatasT) addFromLastPressure(data *LpDBT) {
	vti := p.find(data.SN)
	vti.CardID = data.CardID
	vti.SID = data.SID
	vti.Temperature = data.Temperature
	vti.Pressure = data.Pressure
	vti.Volume = data.Volume
	vti.Active = true
	vti.T = data.T
}

type VehicleTiresT struct {
	Type  int                  `json:"type"`
	Vid   string               `json:"vid"`
	Rid   string               `json:"rid"`
	Datas []*VehicleTireDatasT `json:"datas"`
}

func (p *VehicleTiresT) find(cardid int) *VehicleTireDatasT {
	for i := 0; i < len(p.Datas); i++ {
		if p.Datas[i].CardID == cardid {
			return p.Datas[i]
		}
	}
	vtd := VehicleTireDatasT{CardID: cardid, Tires: make([]*VehicleTireInfoT, 0)}
	p.Datas = append(p.Datas, &vtd)
	return &vtd
}

func (p *VehicleTiresT) add(data *VehicleTireInfoT) {
	vdt := p.find(data.CardID)
	vdt.Tires = append(vdt.Tires, data)
}

func (p *VehicleTiresT) addFromLastPressure(data *LpDBT) {
	vtd := p.find(data.CardID)
	vtd.addFromLastPressure(data)
}

type LpDBT struct {
	CardID      int     `bson:"cardid"`
	SN          int     `bson:"sn"`
	SID         string  `bson:"sid"`
	Temperature int     `bson:"temp"`
	Pressure    float32 `bson:"pres"`
	Volume      float32 `bson:"vol"`
	T           int     `bson:"t"`
}

type LwDBT struct {
	CardID int    `bson:"cardid"`
	SN     int    `bson:"sn"`
	SID    string `bson:"sid"`
	Type   int    `bson:"type"`
	Stat   int    `bson:"stat"`
}

type LastStatusDBT struct {
	Lp []LpDBT `bson:"lp"`
	Lw []LwDBT `bson:"lw"`
}

func (p *LastStatusDBT) warnType(cardid, sn int) string {
	wt := ""

	for _, v := range p.Lw {
		if v.Stat == 0 && v.CardID == cardid && v.SN == sn {
			wt += strconv.Itoa(v.Type) + ","
		}
	}
	if wt != "" {
		wt = wt[:len(wt)-1]
	}
	return wt
}

func (p *DBOperation) receiverTires(rid string) (*VehicleTiresT, error) {
	var vt VehicleTiresT

	vt.Rid = rid
	vt.Vid = p.getVidByRid(rid)
	vt.Type = p.receiverType(rid)
	vt.Datas = make([]*VehicleTireDatasT, 0)

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionRelations)
	var resTires []*VehicleTireInfoT

	err := c.Find(bson.M{"rid": rid, "$or": []bson.M{{"sid": bson.M{"$exists": 1}}, {"tno": bson.M{"$exists": 1}}}}).
		Select(bson.M{"_id": 0, "sid": 1, "sn": 1, "cardid": 1, "tno": 1}).
		All(&resTires)
	if err == nil {
		for _, v := range resTires {
			if v.SID != "" || v.TireNO != "" {
				vt.add(v)
			}
		}
	}

	c = s.DB(p.dbName).C(CollectionLastStatuses)
	var ls LastStatusDBT
	err = c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "lp": 1, "lw": 1}).One(&ls)
	if err == nil {
		for _, v := range ls.Lp {
			vt.addFromLastPressure(&v)
		}
		var pDatas *VehicleTireDatasT
		var pTires *VehicleTireInfoT
		for i := 0; i < len(vt.Datas); i++ {
			pDatas = vt.Datas[i]
			for j := 0; j < len(pDatas.Tires); j++ {
				pTires = pDatas.Tires[j]
				pTires.Warn = ls.warnType(pTires.CardID, pTires.SN)
			}
		}
	}

	return &vt, nil
}

func (p *DBOperation) vehicleTires(vid string) (*VehicleTiresT, error) {
	rid := p.getRidByVid(vid)
	if rid == "" {
		return nil, errors.New("not fund")
	}
	return p.receiverTires(rid)
}

func (p *DBOperation) vehicleTires_v2(vid string) (*VehicleTiresT, error) {
	var vt VehicleTiresT

	vt.Rid = p.getRidByVid(vid)
	vt.Vid = vid
	vt.Type = p.vehicleType(vid)
	vt.Datas = make([]*VehicleTireDatasT, 0)

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionRelations)
	var resTires []*VehicleTireInfoT
	bsonQuery := bson.M{}
	//如果有Rid，则以Rid来查询关联关系
	if vt.Rid != "" {
		bsonQuery["rid"] = vt.Rid
	} else {
		bsonQuery["vid"] = vid
	}
	bsonQuery["cardid"] = bson.M{"$exists": true}
	err := c.Find(bsonQuery). //bson.M{"vid": vid, "cardid": bson.M{"$exists": true}}
					Select(bson.M{"_id": 0, "sid": 1, "sn": 1, "cardid": 1, "tno": 1}).
		//Sort("cardid,sn").
		All(&resTires)
	if err == nil {
		for _, v := range resTires {
			vt.add(v)
		}
	}

	if vt.Rid != "" {
		c = s.DB(p.dbName).C(CollectionLastStatuses)
		var ls LastStatusDBT
		err = c.Find(bson.M{"rid": vt.Rid}).Select(bson.M{"_id": 0, "lp": 1, "lw": 1}).One(&ls)
		if err == nil {
			for _, v := range ls.Lp {
				vt.addFromLastPressure(&v)
			}
			var pDatas *VehicleTireDatasT
			var pTires *VehicleTireInfoT
			for i := 0; i < len(vt.Datas); i++ {
				pDatas = vt.Datas[i]
				for j := 0; j < len(pDatas.Tires); j++ {
					pTires = pDatas.Tires[j]
					pTires.Warn = ls.warnType(pTires.CardID, pTires.SN)
				}
			}
		}
	}

	return &vt, nil
}

func (p *DBOperation) getVidByRid(rid string) string {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	var res map[string]string

	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "vid": 1}).One(&res)
	if err == nil {
		if vid, ok := res["vid"]; ok {
			return vid
		}
	}
	return ""
}

func (p *DBOperation) getRidByVid(vid string) string {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	var res map[string]string

	err := c.Find(bson.M{"vid": vid}).Select(bson.M{"_id": 0, "rid": 1}).One(&res)
	if err == nil {
		if rid, ok := res["rid"]; ok {
			return rid
		}
	}
	return ""
}

func (p *DBOperation) getRidByPlate(plate string) string {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	var res map[string]string

	err := c.Find(bson.M{"plate": plate}).Select(bson.M{"_id": 0, "rid": 1}).One(&res)
	if err == nil {
		if rid, ok := res["rid"]; ok {
			return rid
		}
	}
	return ""
}

func (p *DBOperation) driverBriefInfo(driverId string) *DriverBriefInfoT {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionDrivers)
	var res DriverBriefInfoT
	err := c.Find(bson.M{"did": driverId}).Select(bson.M{"_id": 0, "did": 1, "name": 1, "phone": 1}).One(&res)
	if err != nil {
		return nil
	}
	return &res
}

func (p *DBOperation) getVehicleBrandAndModel(vbid, vmid string) (string, string) {
	type BrandAndModelT struct {
		Name   string `bson:"name"`
		VmName string `bson:"vmname"`
	}
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicleBrands)
	var bm BrandAndModelT

	bsonQuery := bson.M{"vbid": vbid}
	if vmid != "" {
		bsonQuery["vmid"] = vmid
	}
	err := c.Find(bsonQuery).Select(bson.M{"_id": 0, "name": 1, "vmname": 1}).One(&bm)
	if err != nil {
		return "", ""
	}
	return bm.Name, bm.VmName
}

type VehicleInfoDBT struct {
	Vid         string   `bson:"vid" json:"vid"`
	BrandID     string   `bson:"vbid" json:"-"`
	ModelID     string   `bson:"vmid" json:"-"`
	Dom         int      `bson:"dom" json:"dom"`
	Dop         int      `bson:"dop" json:"dop"`
	Payload     int      `bson:"sp" json:"payload"`
	RealPayload int      `bson:"rp" json:"realpayload"`
	Cid         int      `bson:"cid" json:"cid"`
	Tid         string   `bson:"tid" json:"tid"`
	Tids        []string `bson:"tids" json:"tids"`
	Rid         string   `bson:"rid" json:"rid"`
	DriverIDs   []string `bson:"dids" json:"-"`
	Plate       string   `bson:"plate" json:"plate"`
	Frame       string   `bson:"frame" json:"frame"`
	Type        int      `bson:"type" json:"type"`
	InitMileage int      `bson:"ima" json:"initmileage"`
	EngineType  int      `bson:"enginetype" json:"enginetype"`
}

func (p *DBOperation) vehicleAdd2(v *VehicleInfoDBT) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicles)
	var err error

	query := bson.M{} //make(map[string]interface{})
	var res map[string]interface{}
	if v.Plate != "" {
		query["plate"] = v.Plate
	}
	if v.Frame != "" {
		query["frame"] = v.Frame
	}
	if v.Plate != "" || v.Frame != "" {
		err = c.Find(query).Select(bson.M{"_id": 0}).One(&res)
		if err == nil {
			return errors.New("已存在此车辆")
		}
	}

	err = c.Insert(v)
	if err != nil {
		return err
	}

	if v.Rid != "" {
		c = s.DB(p.dbName).C(CollectionReceivers)
		c.Update(bson.M{"rid": v.Rid}, bson.M{"$set": bson.M{"vid": v.Vid, "plate": v.Plate}})
		p.setReceiverType(v.Rid, v.Type)

		p.addReceiverToCompany(v.Cid, v.Rid)
	}

	p.addVehicleToCompany(v.Cid, v.Vid)

	if v.Tid != "" {
		tids := p.getTeamParents(v.Tid)
		for _, tid := range tids {
			p.addVehicleToTeam(tid, v.Vid)

			if v.Rid != "" {
				p.addReceiverToTeam(tid, v.Rid)
			}
		}
	}

	return nil
}

func (p *DBOperation) addReceiverToCompany(cid int, rid string) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	if c.Find(bson.M{"rid": rid, "cid": cid}).Select(bson.M{"_id": 1}).One(nil) != nil {
		c.Update(bson.M{"rid": rid}, bson.M{"$set": bson.M{"cid": cid}})
	}

	c = s.DB(p.dbName).C(CollectionOrganizationProperties)
	var res map[string]interface{}

	err := c.Find(bson.M{"cid": cid, "rid": rid}).Select(bson.M{"_id": 1}).One(&res)
	if err != nil {
		c.Insert(bson.M{"cid": cid, "rid": rid})
	}
}

func (p *DBOperation) addReceiverToTeam(tid string, rid string) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	if c.Find(bson.M{"rid": rid, "tids": tid}).Select(bson.M{"_id": 1}).One(nil) != nil {
		c.Update(bson.M{"rid": rid}, bson.M{"$push": bson.M{"tids": tid}})
	}

	c = s.DB(p.dbName).C(CollectionOrganizationProperties)
	var res map[string]interface{}

	err := c.Find(bson.M{"tid": tid, "rid": rid}).Select(bson.M{"_id": 1}).One(&res)
	if err != nil {
		c.Insert(bson.M{"tid": tid, "rid": rid})
	}
}

func (p *DBOperation) removeReceiverFromTeam(tid string, rid string) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	if c.Find(bson.M{"rid": rid, "tids": tid}).Select(bson.M{"_id": 1}).One(nil) != nil {
		c.Update(bson.M{"rid": rid}, bson.M{"$pull": bson.M{"tids": tid}})
	}
}

func (p *DBOperation) addVehicleToCompany(cid int, vid string) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionOrganizationProperties)
	var res map[string]interface{}

	err := c.Find(bson.M{"cid": cid, "vid": vid}).Select(bson.M{"_id": 1}).One(&res)
	if err != nil {
		c.Insert(bson.M{"cid": cid, "vid": vid})
	}

	c = s.DB(p.dbName).C(CollectionVehicles)
	err = c.Find(bson.M{"vid": vid, "cid": cid}).Select(bson.M{"_id": 1}).One(nil)
	if err == nil {
		c.Update(bson.M{"vid": vid}, bson.M{"$set": bson.M{"cid": cid}})

	}
}

func (p *DBOperation) addVehicleToTeam(tid string, vid string) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionOrganizationProperties)
	var res map[string]interface{}

	err := c.Find(bson.M{"tid": tid, "vid": vid}).Select(bson.M{"_id": 1}).One(&res)
	if err != nil {
		c.Insert(bson.M{"tid": tid, "vid": vid})
	}

	c = s.DB(p.dbName).C(CollectionVehicles)
	err = c.Find(bson.M{"vid": vid, "tids": tid}).Select(bson.M{"_id": 1}).One(nil)
	if err == nil {
		c.Update(bson.M{"vid": vid}, bson.M{"$push": bson.M{"tids": tid}})

	}
}

func (p *DBOperation) getTeamParents(tid string) []string { //[]bson.ObjectId {
	ret := make([]string, 0)
	if tid == "" {
		return ret
	}

	s := p.session.Copy()
	defer s.Close()

	var res map[string]string
	var err error

	newTid := tid
	c := s.DB(p.dbName).C(CollectionTeams)
	for {
		err = c.Find(bson.M{"tid": newTid}).Select(bson.M{"pid": 1}).One(&res)
		if err != nil {
			break
		}
		newTid = res["pid"]
		if newTid == "" || !bson.IsObjectIdHex(tid) {
			break
		}
		ret = append(ret, newTid)
	}

	ret = append(ret, tid)

	return ret
}

func (p *DBOperation) getTeamChilden(tid string) []string {
	s := p.session.Copy()
	defer s.Close()

	ret := make([]string, 0)
	var res []map[string]string
	var err error

	ret = append(ret, tid)

	c := s.DB(p.dbName).C(CollectionTeams)
	err = c.Find(bson.M{"pid": tid}).Select(bson.M{"_id": 0, "tid": 1}).All(&res)
	if err != nil || len(res) == 0 {
		return ret
	}
	for _, v := range res {
		tids := p.getTeamChilden(v["tid"])
		ret = append(ret, tids...)
	}

	return ret
}

type CustomerT struct {
	Cid      int    `bson:"cid" json:"cid"`
	User     string `bson:"user" json:"user"`
	Name     string `bson:"uname" json:"name"`
	UType    int    `bson:"utype" json:"utype"`
	Phone    string `bson:"phone" json:"phone"`
	EMail    string `bson:"email" json:"email"`
	Tid      string `bson:"tid" json:"tid"`
	TeamName string `json:"teamname"`
	Locked   int    `json:"locked" bson:"locked"`
}

func (p *DBOperation) customerList(userid string, cid int, tid string) ([]CustomerT, error) {
	s := p.session.Copy()
	defer s.Close()

	if cid == 0 {
		userType := p.userType(userid)
		if userType != UserTypeSystemUser {
			return nil, errors.New("无此权限")
		}
	}

	var res []CustomerT
	c := s.DB(p.dbName).C(CollectionCustomers)

	query := bson.M{}
	if cid != 0 {
		query["cid"] = cid
	}
	if tid != "" {
		tids := p.getTeamChilden(tid)
		query["tid"] = bson.M{"$in": tids}
	}
	err := c.Find(query).All(&res)
	if err != nil {
		return nil, err
	}

	for i := 0; i < len(res); i++ {
		if res[i].Tid != "" {
			res[i].TeamName = p.getTeamName(res[i].Tid)
		} else {
			res[i].TeamName = p.getCompanyName(res[i].Cid)
		}
	}

	return res, nil
}

func (p *DBOperation) addCustomer(customer map[string]interface{}) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCustomers)

	var res interface{}
	user := customer["user"].(string)
	err := c.Find(bson.M{"user": user}).Select(bson.M{"_id": 1}).One(&res)
	if err == nil {
		return errors.New("已经存在此用户名")
	}

	return c.Insert(customer)
}

func (p *DBOperation) editCustomer(user, name, pass, phone, mail string, utype int) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCustomers)

	bsonUpdate := bson.M{"uname": name, "phone": phone, "utype": utype}
	if pass != "" {
		bsonUpdate["pass"] = pass
	}
	if mail != "" {
		bsonUpdate["email"] = mail
	}

	return c.Update(bson.M{"user": user}, bson.M{"$set": bsonUpdate})
}

func (p *DBOperation) customerChangePassword(operator string, user string, pass string) error {
	if !bson.IsObjectIdHex(operator) {
		return errors.New("无效的操作人ID")
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCustomers)
	return c.Update(bson.M{"user": user}, bson.M{"$set": bson.M{"pass": pass}})
}

func (p *DBOperation) customerRemove(cid int, user string) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCustomers)
	return c.Remove(bson.M{"cid": cid, "user": user})
}

func (p *DBOperation) customerUnbindWechat(userid, wxId string) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCustomers)
	uid := bson.ObjectIdHex(userid)

	var res map[string]string
	err := c.Find(bson.M{"_id": uid}).Select(bson.M{"_id": 0, "wxid": 1, "wxname": 1}).One(&res)
	if err != nil {
		return err
	}
	if res["wxid"] != wxId {
		wxName := res["wxname"]
		err = errors.New("该账号只能由" + wxName + "解绑！")
		return err
	}

	c.Update(bson.M{"_id": uid}, bson.M{"$set": bson.M{"wxid": "", "wxname": "", "wxheadimgurl": ""}})
	return nil
}

func (p *DBOperation) driverUnbindMiniProgram(user string) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCustomers)

	c.Update(bson.M{"user": user}, bson.M{"$set": bson.M{"wxid": "", "wxname": "", "wxheadimgurl": ""}})
	return nil
}

type LoginHistoryT struct {
	Cid     int    `bson:"cid" json:"cid"`
	UserId  string `bson:"userid" json:"userid"`
	User    string `bson:"user" json:"user"`
	Name    string `bson:"name" json:"name"`
	Date    int    `bson:"d" json:"date"`
	Time    int    `bson:"t" json:"time"`
	IP      string `bson:"ip" json:"ip"`
	Address string `bson:"addr" json:"addr"`
}

func (p *DBOperation) customerLoginHistory(cid int, user string, date int, page int) (int, []LoginHistoryT) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionLoginHistories)
	var res []LoginHistoryT
	query := bson.M{"cid": cid}
	if user != "" {
		query["user"] = user
	}
	if date > 0 {
		query["d"] = date
	}
	total, _ := c.Find(query).Count()

	err := c.Find(query).Select(bson.M{"_id": 0}).Limit(10).Skip(page * 10).Sort("-_id").All(&res)
	if err != nil {
		res = make([]LoginHistoryT, 0)
	}
	return total, res
}

type TireWarningT struct {
	OID         bson.ObjectId `bson:"_id" json:"-"`
	ID          string        `json:"id"`
	Cid         int           `json:"cid"`
	Tid         string        `json:"tid"`
	Team        string        `json:"team"`
	Rid         string        `bson:"rid" json:"rid"`
	D           int64         `bson:"date" json:"-"`
	T           int64         `bson:"time" json:"-"`
	Dt          int64         `json:"time"`
	Card        int           `bson:"cardid" json:"card"`
	SN          int           `bson:"sn" json:"sn"`
	WT          int           `bson:"wt" json:"warntype"`
	Level       int           `json:"level"`
	Stat        int           `bson:"stat" json:"stat"`
	Vid         string        `json:"vid"`
	RealRid     string        `json:"realrid"`
	VehicleType int           `json:"vehicletype"`
}

func (p *DBOperation) tireWarningList(userid string, rid string, date string, stype string, cardid, sn, status int, page int) (int, []TireWarningT) {
	var ret []TireWarningT = make([]TireWarningT, 0)

	var rids []string
	var iDate, iType, iUserType int
	var err error

	if date != "" {
		iDate, err = strconv.Atoi(date)
		if err != nil {
			return 0, ret
		}
	}
	if stype != "" {
		iType, err = strconv.Atoi(stype)
		if err != nil {
			return 0, ret
		}
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireWarnings)
	query := bson.M{}

	iUserType = p.userType(userid)

	if iUserType == UserTypeSystemUser && rid == "" {
	} else {
		rids = p.userReceivers(userid, rid)
		query["rid"] = bson.M{"$in": rids}
	}
	if iDate != 0 {
		query["date"] = iDate
	}
	if stype != "" {
		query["wt"] = iType
	}
	if status != 3 {
		query["stat"] = status
	}
	if cardid != -1 {
		query["cardid"] = cardid
	}
	if sn != -1 {
		query["sn"] = sn
	}

	total, _ := c.Find(query).Count()

	c.Find(query).Select(bson.M{"_id": 1, "rid": 1, "date": 1, "time": 1, "cardid": 1, "sn": 1, "wt": 1, "stat": 1}).
		Skip(page * 20).Limit(20).Sort("-_id").All(&ret)

	var tw *TireWarningT
	var plate string
	var TName string

	for i := 0; i < len(ret); i++ {
		tw = &ret[i]
		tw.ID = tw.OID.Hex()
		tw.Dt = tw.D*1000000 + tw.T
		if tw.WT == 1 || tw.WT == 5 {
			tw.Level = 0
		} else if tw.WT == 2 || tw.WT == 3 || tw.WT == 4 {
			tw.Level = 1
		} else {
			tw.Level = 2
		}
		tw.RealRid = tw.Rid
		tw.Cid, tw.Team = p.getCompanyNameByRid(tw.Rid)
		tw.Tid, TName = p.getTeamNameByRid(tw.Rid)
		if TName != "" {
			tw.Team = TName
		}
		plate, _, _, _, tw.Vid, tw.VehicleType = p.getPlateByRid(tw.Rid)
		if plate != "" {
			tw.Rid = plate
		}
	}

	return total, ret
}

func (p *DBOperation) tireWarningListV2(cids []int, tids []string, rid string, date string, stype string, cardid, sn, status int, page int) (int, []TireWarningT) {
	var ret []TireWarningT = make([]TireWarningT, 0)

	var rids []string
	var iDate, iType int
	var err error

	if date != "" {
		iDate, err = strconv.Atoi(date)
		if err != nil {
			return 0, ret
		}
	}
	if stype != "" {
		iType, err = strconv.Atoi(stype)
		if err != nil {
			return 0, ret
		}
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireWarnings)
	query := bson.M{}

	rids = p.getRidsByCidsAndTids(cids, tids, rid)
	if len(rids) != 0 {
		query["rid"] = bson.M{"$in": rids}
	} else {
		return 0, ret
	}

	if iDate != 0 {
		query["date"] = iDate
	}
	if stype != "" {
		query["wt"] = iType
	}
	if status != 3 {
		//不是全部，则加入status
		query["stat"] = status
	}
	if cardid != -1 {
		query["cardid"] = cardid
	}
	if sn != -1 {
		query["sn"] = sn
	}

	total, _ := c.Find(query).Count()

	c.Find(query).Select(bson.M{"_id": 1, "rid": 1, "date": 1, "time": 1, "cardid": 1, "sn": 1, "wt": 1, "stat": 1}).
		Skip(page * 20).Limit(20).Sort("-_id").All(&ret)

	var tw *TireWarningT
	var plate, TName string

	for i := 0; i < len(ret); i++ {
		tw = &ret[i]
		tw.ID = tw.OID.Hex()
		tw.Dt = tw.D*1000000 + tw.T
		if tw.WT == 1 || tw.WT == 5 {
			tw.Level = 0
		} else if tw.WT == 2 || tw.WT == 3 || tw.WT == 4 {
			tw.Level = 1
		} else {
			tw.Level = 2
		}
		tw.RealRid = tw.Rid
		tw.Cid, tw.Team = p.getCompanyNameByRid(tw.Rid)
		tw.Tid, TName = p.getTeamNameByRid(tw.Rid)
		if TName != "" {
			tw.Team = TName
		}

		plate, _, _, _, tw.Vid, tw.VehicleType = p.getPlateByRid(tw.Rid)
		if plate != "" {
			tw.Rid = plate
		}
	}

	return total, ret
}

func (p *DBOperation) tireWarningListV3(cids []int, tids []string, rid string, date string, stype string,
	cardid, sn, status int, page, count int) (int, []TireWarningT) {
	var ret []TireWarningT = make([]TireWarningT, 0)

	var rids []string
	var iDate, iType int
	var err error

	if date != "" {
		iDate, err = strconv.Atoi(date)
		if err != nil {
			return 0, ret
		}
	}
	if stype != "" {
		iType, err = strconv.Atoi(stype)
		if err != nil {
			return 0, ret
		}
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireWarnings)
	query := bson.M{}

	if len(cids) > 0 || len(tids) > 0 {
		rids = p.getRidsByCidsAndTids(cids, tids, rid)
		if len(rids) != 0 {
			if rid != "" {
				rids = append(rids, rid)
			}
			query["rid"] = bson.M{"$in": rids}
		} else {
			return 0, ret
		}
	} else if rid != "" {
		query["rid"] = rid
	}

	if iDate != 0 {
		query["date"] = iDate
	}
	if stype != "" {
		query["wt"] = iType
	}
	if status != 3 {
		//不是全部，则加入status
		query["stat"] = status
	}
	if cardid != -1 {
		query["cardid"] = cardid
	}
	if sn != -1 {
		query["sn"] = sn
	}

	total, _ := c.Find(query).Count()

	c.Find(query).Select(bson.M{"_id": 1, "rid": 1, "date": 1, "time": 1, "cardid": 1, "sn": 1, "wt": 1, "stat": 1}).
		Skip(page * count).Limit(count).Sort("-_id").All(&ret)

	var tw *TireWarningT
	var plate, TName string

	for i := 0; i < len(ret); i++ {
		tw = &ret[i]
		tw.ID = tw.OID.Hex()
		tw.Dt = tw.D*1000000 + tw.T
		if tw.WT == 1 || tw.WT == 5 {
			tw.Level = 0
		} else if tw.WT == 2 || tw.WT == 3 || tw.WT == 4 {
			tw.Level = 1
		} else {
			tw.Level = 2
		}
		tw.RealRid = tw.Rid
		tw.Cid, tw.Team = p.getCompanyNameByRid(tw.Rid)
		tw.Tid, TName = p.getTeamNameByRid(tw.Rid)
		if TName != "" {
			tw.Team = TName
		}

		plate, _, _, _, tw.Vid, tw.VehicleType = p.getPlateByRid(tw.Rid)
		if plate != "" {
			tw.Rid = plate
		}
	}

	return total, ret
}

func (p *DBOperation) getRidsByCidsAndTids(cids []int, tids []string, rid string) []string {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	rids := make([]string, 0)
	var res []map[string]string
	bsonQuery := bson.M{}
	if len(cids) > 0 && len(tids) > 0 {
		bsonQuery["$or"] = []bson.M{{"cid": bson.M{"$in": cids}}, {"tids": bson.M{"$in": tids}}}
	} else if len(cids) > 0 {
		bsonQuery["cid"] = bson.M{"$in": cids}
	} else if len(tids) > 0 {
		bsonQuery["tids"] = bson.M{"$in": tids}
	}
	if rid != "" {
		bsonQuery["rid"] = rid
	}

	err := c.Find(bsonQuery).Select(bson.M{"_id": 0, "rid": 1}).All(&res)
	if err == nil {
		for _, v := range res {
			rids = append(rids, v["rid"])
		}
	}

	return rids
}

func (p *DBOperation) getTeamNameByRid(rid string) (string, string) {
	if rid == "" {
		return "", ""
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	var res map[string][]string

	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"tids": 1, "_id": 0}).One(&res)
	if err != nil {
		return "", ""
	}

	tids := res["tids"]
	iLen := len(tids)
	if iLen == 0 {
		return "", ""
	}
	tid := tids[iLen-1] //如果有多个车队，只返回最后的一个

	return tid, p.getTeamName(tid)
}

func (p *DBOperation) getCompanyNameByRid(rid string) (int, string) {
	if rid == "" {
		return 0, ""
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	var res map[string]int

	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "cid": 1}).One(&res)
	if err != nil {
		return 0, ""
	}

	cid := res["cid"]
	if cid == 0 {
		return 0, ""
	}

	return cid, p.getCompanyName(cid)
}

func (p *DBOperation) getCompanyAndTeamByRid(rid string) (int, []string) {
	if rid == "" {
		return 0, nil
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	var res struct {
		Cid  int      `bson:"cid"`
		Tids []string `bson:"tids"`
	}

	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "cid": 1, "tids": 1}).One(&res)
	if err != nil {
		return 0, nil
	}

	return res.Cid, res.Tids
}

func (p *DBOperation) getCompanyAndTeamByVid(vid string) (int, []string) {
	if vid == "" {
		return 0, nil
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicles)
	var res struct {
		Cid int    `bson:"cid"`
		Tid string `bson:"tid"`
	}

	err := c.Find(bson.M{"vid": vid}).Select(bson.M{"_id": 0, "cid": 1, "tid": 1}).One(&res)
	if err != nil {
		return 0, nil
	}

	var tids []string

	if res.Tid != "" {
		tids = p.getTeamParents(res.Tid)
	} else {
		tids = make([]string, 0)
	}

	return res.Cid, tids
}

type TireWarningDetailT struct {
	Oid_ bson.ObjectId `bson:"oid" json:"-"`
	Orid string        `json:"orid"`
	Rid  string        `bson:"rid" json:"rid"`
	D    int64         `bson:"date" json:"-"`
	T    int64         `bson:"time" json:"-"`
	DT   int64         `json:"time"`
	Card int           `bson:"cardid" json:"card"`
	SN   int           `bson:"sn" json:"sn"`
	//WType int `bson:"type" json"warntype"`
	Sid   string  `bson:"sid" json:"sid"`
	LatW  float64 `bson:"lat" json:"-"`
	LngW  float64 `bson:"lng" json:"-"`
	LatB  float64 `bson:"latb" json:"-"`
	LngB  float64 `bson:"lngb" json:"-"`
	LatG  float64 `bson:"latg" json:"-"`
	LngG  float64 `bson:"lngg" json:"-"`
	Lati  float64 `json:"latitude"`
	Long  float64 `json:"longitude"`
	Vol   float64 `bson:"vol" json:"vol"`
	Pres  float64 `bson:"pres" json:"pres"`
	Temp  int     `bson:"temp" json:"temp"`
	Wt    int     `bson:"wt" json:"warntype"`
	Stat  int     `bson:"stat" json:"stat"`
	Level int     `json:"level"`
}

func (p *DBOperation) tireWarningDetail(id string, gpstype string) (*TireWarningDetailT, error) {
	if !bson.IsObjectIdHex(id) {
		return nil, errors.New("无效的报警号")
	}

	s := p.session.Copy()
	defer s.Close()

	var detail TireWarningDetailT
	_id := bson.ObjectIdHex(id)
	c := s.DB(p.dbName).C(CollectionTireWarnings)
	var selectField bson.M = bson.M{"_id": 1, "oid": 1, "rid": 1, "date": 1, "time": 1, "cardid": 1, "sn": 1, "type": 1, "sid": 1,
		"vol": 1, "pres": 1, "temp": 1, "wt": 1, "stat": 1}

	if gpstype == GpsBd09 {
		selectField["latb"] = 1
		selectField["lngb"] = 1
	} else if gpstype == GpsGCJ02 {
		selectField["latg"] = 1
		selectField["lngg"] = 1
	} else {
		selectField["lat"] = 1
		selectField["lng"] = 1
	}
	err := c.Find(bson.M{"_id": _id}).Select(selectField).One(&detail)
	if err != nil {
		return nil, err
	}
	detail.Orid = detail.Oid_.Hex()
	detail.DT = detail.D*1000000 + detail.T
	if gpstype == GpsBd09 {
		detail.Lati = detail.LatB
		detail.Long = detail.LngB
	} else if gpstype == GpsGCJ02 {
		detail.Lati = detail.LatG
		detail.Long = detail.LngG
	} else {
		detail.Lati = detail.LatW
		detail.Long = detail.LngW
	}
	if detail.Wt == 1 || detail.Wt == 5 {
		detail.Level = 0
	} else if detail.Wt == 2 || detail.Wt == 3 || detail.Wt == 4 {
		detail.Level = 1
	} else {
		detail.Level = 2
	}

	return &detail, nil
}

type TireBrandT struct {
	Cid     int    `bson:"cid" json:"cid"`
	BrandID int    `bson:"tbid" json:"id"`
	Name    string `bson:"name" json:"name"`
}

func (p *DBOperation) tireBrandList(userid string, cid int, page int) (int, []TireBrandT) {
	s := p.session.Copy()
	defer s.Close()

	var tb []TireBrandT
	c := s.DB(p.dbName).C(CollectionTireBrands)
	bsonQuery := bson.M{}
	userType := p.userType(userid)
	if userType != UserTypeSystemUser {
		if cid == 0 {
			//非系统管理员，cid不允许为0
			return 0, make([]TireBrandT, 0)
		}
		bsonQuery["cid"] = cid
	} else {
		if cid != 0 {
			bsonQuery["cid"] = cid
		}
	}

	count, _ := c.Find(bsonQuery).Count()

	if count == 0 {
		tb = make([]TireBrandT, 0)
	} else {
		query := c.Find(bsonQuery).Select(bson.M{"_id": 0, "cid": 1, "tbid": 1, "name": 1}).Sort("name")
		if page >= 0 {
			query = query.Skip(page * 10).Limit(10)
		}
		err := query.All(&tb)
		if err != nil {
			tb = make([]TireBrandT, 0)
		}
	}
	return count, tb
}

func (p *DBOperation) tireBrandAdd(cid int, name string) (int, error) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireBrands)
	var res map[string]int
	var tbid int

	err := c.Find(bson.M{"cid": cid, "name": name}).Select(bson.M{"_id": 0}).One(nil)
	if err == nil {
		return 0, errors.New("已经存在重复纪录")
	}

	err = c.Find(bson.M{"cid": cid}).Sort("-tbid").Select(bson.M{"_id": 0, "tbid": 1}).Limit(1).One(&res)
	if err != nil {
		tbid = cid * 10000
	} else {
		tbid = res["tbid"] + 1
	}

	err = c.Insert(bson.M{"cid": cid, "tbid": tbid, "name": name})

	return tbid, err
}

func (p *DBOperation) tireBrandEdit(cid int, brandId int, name string) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireBrands)
	var res map[string]string

	err := c.Find(bson.M{"cid": cid, "tbid": brandId}).Select(bson.M{"_id": 0, "name": 1}).One(&res)
	if err == nil {
		if name != res["name"] {
			err = c.Update(bson.M{"cid": cid, "tbid": brandId}, bson.M{"$set": bson.M{"name": name}})
		}
	}
	return err
}

func (p *DBOperation) tireBrandRemove(cid int, brandId int) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireBrands)
	c.Remove(bson.M{"cid": cid, "tbid": brandId})
}

func (p *DBOperation) tireBrandNameToID(cid int, brand string) int {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireBrands)
	var res map[string]int
	err := c.Find(bson.M{"cid": cid, "name": brand}).Select(bson.M{"_id": 0, "tbid": 1}).One(&res)
	if err == nil {
		return res["tbid"]
	}
	return 0
}

type TireModelT struct {
	ModelID  string  `bson:"tmid" json:"model"`
	Name     string  `bson:"name" json:"name"`
	Pattern  string  `bson:"pattern" json:"pattern"`
	Depth    float32 `bson:"pdepth" json:"depth"`
	Mileage  int     `bson:"mileage" json:"mileage"`
	Pressure float32 `bson:"maxpres" json:"pressure"`
	Load     int     `bson:"maxload" json:"load"`
}

func (p *DBOperation) tireModelList(brandID int, page int) (int, []TireModelT) {
	s := p.session.Copy()
	defer s.Close()

	var tb []TireModelT
	c := s.DB(p.dbName).C(CollectionTireModels)
	total, err := c.Find(bson.M{"tbid": brandID}).Count()
	if err != nil {
		return 0, make([]TireModelT, 0)
	}

	query := c.Find(bson.M{"tbid": brandID}).
		Select(bson.M{"_id": 0, "tmid": 1, "name": 1, "pattern": 1, "pdepth": 1, "mileage": 1, "maxpres": 1, "maxload": 1})
	if page >= 0 {
		query = query.Skip(page * 10).Limit(10)
	}
	err = query.All(&tb)
	if err != nil {
		tb = make([]TireModelT, 0)
	}
	return total, tb
}

func (p *DBOperation) tireModelInfo(brandId int, model, pattern string) *TireModelT {
	s := p.session.Copy()
	defer s.Close()

	var tb TireModelT
	c := s.DB(p.dbName).C(CollectionTireModels)

	bsonQuery := bson.M{"tbid": brandId, "tmid": model}
	if pattern != "" {
		bsonQuery["pattern"] = pattern
	}
	c.Find(bsonQuery).
		Select(bson.M{"_id": 0, "tmid": 1, "name": 1, "pattern": 1, "pdepth": 1, "mileage": 1, "maxpres": 1, "maxload": 1}).
		One(&tb)

	return &tb
}

func (p *DBOperation) tireModels(brandID int) []string {
	s := p.session.Copy()
	defer s.Close()

	var models []string
	c := s.DB(p.dbName).C(CollectionTireModels)
	err := c.Find(bson.M{"tbid": brandID}).Distinct("tmid", &models)
	if err != nil {
		return make([]string, 0)
	}

	return models
}

func (p *DBOperation) tirePatterns(brandID int, model string) []string {
	s := p.session.Copy()
	defer s.Close()

	var patterns []string
	c := s.DB(p.dbName).C(CollectionTireModels)
	err := c.Find(bson.M{"tbid": brandID, "tmid": model}).Distinct("pattern", &patterns)
	if err != nil {
		return make([]string, 0)
	}

	return patterns
}

func (p *DBOperation) tireModelAdd(cid int, brandId int, modelId string, name string, pattern string,
	depth float64, mileage int, pressure float64, load int) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireModels)

	err := c.Find(bson.M{"cid": cid, "tbid": brandId, "tmid": modelId, "pattern": pattern}).
		Select(bson.M{"_id": 1}).One(nil)
	if err == nil {
		return errors.New("已经存在重复纪录")
	}

	return c.Insert(bson.M{"cid": cid, "tbid": brandId, "tmid": modelId, "name": name, "pattern": pattern,
		"pdepth": depth, "mileage": mileage, "maxpres": pressure, "maxload": load})
}

func (p *DBOperation) tireModelEdit(cid int, brandId int, modelId string, name string, pattern string,
	depth float64, mileage int, pressure float64, load int) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireModels)

	err := c.Find(bson.M{"cid": cid, "tbid": brandId, "tmid": modelId}).Select(bson.M{"_id": 1}).One(nil)
	if err != nil {
		return errors.New("不存在此轮胎规格")
	}

	return c.Update(bson.M{"cid": cid, "tbid": brandId, "tmid": modelId}, bson.M{"$set": bson.M{"name": name, "pattern": pattern,
		"pdepth": depth, "mileage": mileage, "maxpres": pressure, "maxload": load}})
}

func (p *DBOperation) tireModelRemove(cid int, brandId int, modelId string) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireModels)
	c.Remove(bson.M{"cid": cid, "tbid": brandId, "tmid": modelId})
}

func (p *DBOperation) tireSet(cid int, tid string, rid, vid string, cardid int, sn int, brandid int, model, pattern string,
	tireNo string, oldTireNo string, dot string, mileage int, depths string, operator string, operateTime, status int) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTires)
	var res interface{}

	depthArray := make([]float32, 0)
	if depths != "" {
		var dep float64
		depthStrs := strings.Split(depths, ",")
		for _, v := range depthStrs {
			dep, _ = strconv.ParseFloat(v, 32)
			depthArray = append(depthArray, float32(dep))
		}
	}

	bsonData := bson.M{"rid": rid, "vid": vid, "bid": brandid, "mid": model, "pattern": pattern, "ct": time.Now().Unix(),
		"ma": mileage, "cpdepths": depthArray, "operator": operator, "ot": operateTime, "status": status, "wid": 0, "dot": dot}
	if rid != "" {
		bsonData["binded"] = true
		bsonData["bt"] = time.Now().Unix()
	} else {
		bsonData["binded"] = false
		bsonData["bt"] = 0
	}

	ot := time.Now().Unix()
	var opd, opt int

	if operateTime == 0 {
		opd, opt = TimeStampToIntDateAndTime(int(ot))
	} else {
		opd, opt = TimeStampToIntDateAndTime(operateTime)
	}

	var trueCid int
	var tids []string

	if rid != "" {
		trueCid, tids = p.getCompanyAndTeamByRid(rid)
	} else if vid != "" {
		trueCid, tids = p.getCompanyAndTeamByVid(vid)
	}
	if cid == 0 {
		cid = trueCid
	}
	if len(tids) > 0 {
		tid = tids[len(tids)-1]
	}

	tireStatus, tireMileage := p.getTireStatus(cid, tireNo)
	if status != -1 && tireStatus != status {
		tireStatus = status
	}

	ta := TireActionT{Cid: cid, Tid: tid, Wid: 0, Rid: rid, T: ot, Date: opd, Time: opt, Cpdepths: depthArray,
		Operator: operator}

	pDepth := p.tireOriginalDepth(cid, model)
	bsonData["cid"] = cid
	bsonData["tid"] = tid
	bsonData["tids"] = tids

	bsonData["tno"] = tireNo
	bsonData["pdepth"] = pDepth
	bsonData["status"] = tireStatus //TireStatusNew
	bsonData["intodate"] = opd

	err := c.Find(bson.M{"bid": brandid, "tno": tireNo}).Select(bson.M{"_id": 1}).One(&res)
	if err != nil {
		c.Insert(bsonData)

		ta.Action = TireActionStockIn
		if tireStatus == TireStatusUnknow {
			ta.Status = TireStatusNew
		} else {
			ta.Status = tireStatus
		}
		ta.Tno = tireNo
		p.saveTireAction(&ta)
	} else {
		c.Update(bson.M{"bid": brandid, "tno": tireNo}, bson.M{"$set": bsonData})
	}

	ta.Status, ta.Mileage = tireStatus, tireMileage //p.getTireStatus(cid, tireNo)

	if tireNo != oldTireNo {
		ta.Action = TireActionGetOn
		ta.Tno = tireNo
		p.saveTireAction(&ta)

		if oldTireNo != "" {
			c.Update(bson.M{"cid": cid, "tno": oldTireNo}, bson.M{"$set": bson.M{"rid": "", "binded": false}})
			ta.Action = TireActionGetOff
			ta.Tno = oldTireNo
			ta.Status, ta.Mileage = p.getTireStatus(cid, oldTireNo)
			p.saveTireAction(&ta)
		}
	} else {
		ta.Action = TireActionEdit
		ta.Tno = tireNo
		p.saveTireAction(&ta)
	}

	c = s.DB(p.dbName).C(CollectionRelations)
	var bsonQuery, bsonUpdate bson.M

	if rid != "" {
		bsonQuery = bson.M{"rid": rid, "cardid": cardid, "sn": sn}
		err = c.Find(bsonQuery).One(nil)
		if err == nil {
			bsonUpdate = bson.M{"$set": bson.M{"tno": tireNo, "vid": vid}}
			err = c.Update(bsonQuery, bsonUpdate)
		} else {
			err = c.Insert(bson.M{"rid": rid, "vid": vid, "cardid": cardid, "sn": sn, "tno": tireNo})
		}
	} else if vid != "" {
		bsonQuery = bson.M{"vid": vid, "cardid": cardid, "sn": sn}
		err = c.Find(bsonQuery).One(nil)
		if err == nil {
			bsonUpdate = bson.M{"$set": bson.M{"tno": tireNo}}
			err = c.Update(bsonQuery, bsonUpdate)
		} else {
			err = c.Insert(bson.M{"vid": vid, "cardid": cardid, "sn": sn, "tno": tireNo})
		}
	} else {
		err = errors.New("设备号与车辆号不能同时为空！")
	}
	return err
}

func (p *DBOperation) tireOriginalDepth(cid int, model string) float32 {
	s := p.session.Copy()
	defer s.Close()

	var res map[string]float32
	c := s.DB(p.dbName).C(CollectionTireModels)
	err := c.Find(bson.M{"cid": cid, "tmid": model}).Select(bson.M{"_id": 0, "pdepth": 1}).One(&res)
	if err != nil {
		return 0
	}
	return res["pdepth"]
}

func (p *DBOperation) receiverRemoveSN(rid string, cardid int, sn int) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionLastStatuses)
	bsonTemp := bson.M{"cardid": cardid, "sn": sn}
	c.Update(bson.M{"rid": rid}, bson.M{"$pull": bson.M{"lp": bsonTemp, "Lw": bsonTemp}})

	c = s.DB(p.dbName).C(CollectionRelations)
	return c.Remove(bson.M{"rid": rid, "cardid": cardid, "sn": sn})
}

type ReceiverSensorT struct {
	Sid    string `bson:"sid" json:"sid"`
	CardId int    `bson:"cardid" json:"cardid"`
	Sn     int    `bson:"sn" json:"sn"`
}

func (p *DBOperation) receiverSensors(rid string) []ReceiverSensorT {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionRelations)
	var sensors []ReceiverSensorT
	err := c.Find(bson.M{"rid": rid, "sid": bson.M{"$exists": 1}}).
		Select(bson.M{"_id": 0, "sid": 1, "cardid": 1, "sn": 1}).
		Sort("cardid,sn").
		All(&sensors)
	if err != nil {
		sensors = make([]ReceiverSensorT, 0)
	}
	return sensors
}

type RidRelationT struct {
	ID     bson.ObjectId `bson:"_id"`
	Sid    string        `bson:"sid"`
	CardId int           `bson:"cardid"`
	SN     int           `bson:"sn"`
	KeepIt bool          //是否保留该纪录
}

func (p *DBOperation) resetReceiverSensors(rid string, sensors []BindSensorT) {
	s := p.session.Copy()
	defer s.Close()

	cRelation := s.DB(p.dbName).C(CollectionRelations)
	cLastStatus := s.DB(p.dbName).C(CollectionLastStatuses)

	cRelation.RemoveAll(bson.M{"rid": rid})

	cLastStatus.Update(bson.M{"rid": rid}, bson.M{"$unset": bson.M{"lp": 1, "ll": 1, "lw": 1, "lws": 1, "lm": 1}})

	for _, v := range sensors {
		cRelation.Insert(bson.M{"rid": rid, "sid": v.Sid, "cardid": v.CardId, "sn": v.SN})
		cLastStatus.Update(bson.M{"rid": rid},
			bson.M{"$push": bson.M{"lp": bson.M{"cardid": v.CardId, "sn": v.SN, "sid": v.Sid, "t": time.Now().Unix(), "vol": 0, "pres": 0, "temp": 0}}})
	}
}

type ReceiverVidT struct {
	Rid    string `bson:"rid"`
	Vid    string `bson:"vid"`
	Plate  string `bson:"plate"`
	Status int    `bson:"status"`
}

func (p *DBOperation) receiverExchange(userId string, cid int, tid string, oldRid string, newRid string, edate int, etime int,
	invalid int, reason string) error {
	s := p.session.Copy()
	defer s.Close()

	user := p.userId2User(userId)

	c := s.DB(p.dbName).C(CollectionReceivers)
	var rvt []ReceiverVidT //map[string]string
	var vid, plate string

	rids := []string{oldRid, newRid}
	err := c.Find(bson.M{"rid": bson.M{"$in": rids}}).Select(bson.M{"_id": 0, "rid": 1, "vid": 1, "status": 1, "plate": 1}).All(&rvt)
	if err != nil || len(rvt) != 2 {
		return errors.New("没有找到指定的设备，请重新输入")
	}
	for _, v := range rvt {
		if v.Status == -2 {
			return errors.New(v.Rid + "已经作废")
		}
		if v.Rid == oldRid {
			vid = v.Vid
			plate = v.Plate
		}
	}

	c.Update(bson.M{"rid": newRid}, bson.M{"$set": bson.M{"vid": vid, "plate": plate}})
	c.Update(bson.M{"rid": oldRid}, bson.M{"$set": bson.M{"vid": "", "plate": ""}})

	c = s.DB(p.dbName).C(CollectionVehicles)
	c.Update(bson.M{"vid": vid}, bson.M{"$set": bson.M{"rid": newRid}})

	if tid != "" {
		c = s.DB(p.dbName).C(CollectionReceivers)
		if c.Find(bson.M{"rid": newRid, "tids": tid}).Select(bson.M{"_id": 1}).One(nil) != nil {
			c.Update(bson.M{"rid": newRid}, bson.M{"$push": bson.M{"tids": tid}, "$set": bson.M{"tid": tid}})
		}
	}

	var res map[string]string
	c = s.DB(p.dbName).C(CollectionOrganizationProperties)
	err = c.Find(bson.M{"rid": oldRid, "tid": bson.M{"$exists": 1}}).Select(bson.M{"_id": 0, "tid": 1}).One(&res)
	if err == nil {
		tid := res["tid"]
		if tid != "" {
			err = c.Find(bson.M{"rid": newRid, "tid": tid}).Select(bson.M{"_id": 1}).One(&res)
			if err != nil {
				c.Insert(bson.M{"rid": newRid, "tid": tid})
			}
		}
	}
	err = nil

	c = s.DB(p.dbName).C(CollectionRelations)
	c.RemoveAll(bson.M{"rid": newRid})
	c.UpdateAll(bson.M{"rid": oldRid}, bson.M{"$set": bson.M{"rid": newRid}})

	c = s.DB(p.dbName).C(CollectionEquipmentExchanges)
	c.Insert(bson.M{"cid": cid, "tid": tid, "etype": 1, "eidold": oldRid, "eidnew": newRid, "date": edate, "time": etime,
		"operator": user, "reason": reason, "t": time.Now().Unix()})

	if invalid == 1 {
		c = s.DB(p.dbName).C(CollectionEquipmentInvalids)
		c.Insert(bson.M{"cid": cid, "tid": tid, "etype": 1, "eld": oldRid, "date": edate, "time": etime,
			"operator": user, "reason": reason, "t": time.Now().Unix()})

		c = s.DB(p.dbName).C(CollectionReceivers)
		c.Update(bson.M{"rid": oldRid}, bson.M{"$set": bson.M{"status": -2}})

		c = s.DB(p.dbName).C(CollectionLastStatuses)
		err = c.Update(bson.M{"rid": oldRid}, bson.M{"$set": bson.M{"status": -2}})
	}

	return err
}

func (p *DBOperation) receiverInvalid(userId string, cid int, tid string, rid string, idate int, itime int, valid int, reason string) error {
	var status int
	if valid == 0 {
		//作废
		status = ReceiverStatusInvalid
	} else {
		//离线
		status = ReceiverStatusOffline
	}
	p.setReceiverStatus(rid, status)

	s := p.session.Copy()
	defer s.Close()

	user := p.userId2User(userId)

	c := s.DB(p.dbName).C(CollectionEquipmentInvalids)
	return c.Insert(bson.M{"cid": cid, "tid": tid, "etype": 1, "eld": rid, "date": idate, "time": itime,
		"operator": user, "reason": reason, "t": time.Now().Unix()})
}

func (p *DBOperation) userId2User(userid string) string {
	var user string

	if bson.IsObjectIdHex(userid) {
		s := p.session.Copy()
		defer s.Close()

		_id := bson.ObjectIdHex(userid)
		var res map[string]string
		c := s.DB(p.dbName).C(CollectionCustomers)

		err := c.Find(bson.M{"_id": _id}).Select(bson.M{"_id": 0, "user": 1}).One(&res)
		if err == nil {
			user = res["user"]
		}
	} else {
		user = userid
	}

	return user
}

func (p *DBOperation) userId2UserInfo(userid string) (string, string) {
	var user, name string

	if bson.IsObjectIdHex(userid) {
		s := p.session.Copy()
		defer s.Close()

		_id := bson.ObjectIdHex(userid)
		var res map[string]string
		c := s.DB(p.dbName).C(CollectionCustomers)

		err := c.Find(bson.M{"_id": _id}).Select(bson.M{"_id": 0, "user": 1, "uname": 1}).One(&res)
		if err == nil {
			user = res["user"]
			name = res["uname"]
		}
	} else {
		user = userid
	}

	return user, name
}

type MaintenanceSiteLocationT struct {
	Lng float64 `bson:"lng" json:"lng"`
	Lat float64 `bson:"lat" json:"lat"`
}

type MaintenanceSiteT struct {
	Oid           bson.ObjectId            `bson:"_id" json:"-"`
	Id            string                   `bson:"-" json:"id"`
	Cid           int                      `bson:"cid" json:"cid"`
	Tid           string                   `bson:"tid" json:"tid"`
	Name          string                   `bson:"name" json:"name"`
	Address       string                   `bson:"address" json:"address"`
	Location      MaintenanceSiteLocationT `bson:"location" json:"-"`
	Lng           float64                  `bson:"-" json:"lng"`
	Lat           float64                  `bson:"-" json:"lat"`
	Contacts      string                   `bson:"contacts" json:"contacts"`
	Phone         string                   `bson:"phone" json:"phone"`
	WorkerArray   []string                 `bson:"workers" json:"-"`
	WorkerStr     string                   `bson:"-" json:"workers"`
	WorkDayBegin  int                      `bson:"wdbegin" json:"wdbegin"`
	WorkDayEnd    int                      `bson:"wdend" json:"wdend"`
	WorkTimeBegin int                      `bson:"wtbegin" json:"wtbegin"`
	WorkTimeEnd   int                      `bson:"wtend" json:"wtend"`
	Public        bool                     `bson:"public" json:"public"`
	Level         int                      `bson:"level" json:"level"`
	Remark        string                   `bson:"remark" json:"remark"`
}

func (p *DBOperation) maintenanceSiteList(userid string, cid int, tid string, name, address string, page, count int) ([]MaintenanceSiteT, int, error) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionMaintenanceSites)
	var sites []MaintenanceSiteT
	var err error
	var total int

	bsonQuery := bson.M{}
	if !(p.userType(userid) == UserTypeSystemUser && cid == 0) {
		bsonQuery["cid"] = cid
		if tid != "" {
			bsonQuery["tid"] = tid
		}
	}
	if name != "" {
		bsonQuery["name"] = bson.RegEx{Pattern: name, Options: "im"}
	}
	if address != "" {
		bsonQuery["address"] = bson.RegEx{Pattern: address, Options: "im"}
	}

	bsonFields := bson.M{"_id": 1, "cid": 1, "tid": 1, "name": 1, "address": 1, "location": 1, "contacts": 1, "phone": 1, "workers": 1,
		"wdbegin": 1, "wdend": 1, "wtbegin": 1, "wtend": 1, "public": 1, "level": 1, "remark": 1}

	total, err = c.Find(bsonQuery).Select(bsonFields).Count()
	if err != nil || total == 0 {
		return make([]MaintenanceSiteT, 0), 0, err
	}

	err = c.Find(bsonQuery).Select(bsonFields).Sort("-_id").Skip(count * page).Limit(count).All(&sites)
	for i := 0; i < len(sites); i++ {
		sites[i].Id = sites[i].Oid.Hex()
		sites[i].Lng = sites[i].Location.Lng
		sites[i].Lat = sites[i].Location.Lat
		sites[i].WorkerStr = strings.Join(sites[i].WorkerArray, ",")
	}

	return sites, total, err
}

func (p *DBOperation) maintenanceSiteAdd(site *MaintenanceSiteT) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionMaintenanceSites)

	err := c.Find(bson.M{"cid": site.Cid, "tid": site.Tid, "name": site.Name}).Select(bson.M{"_id": 1}).One(nil)
	if err == nil {
		return errors.New("已存在重名的场站")
	}

	return c.Insert(site)
}

func (p *DBOperation) maintenanceSiteEdit(site *MaintenanceSiteT) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionMaintenanceSites)

	bsonUpdate := bson.M{}
	if site.Name != "" {
		bsonUpdate["name"] = site.Name
	}
	bsonUpdate["address"] = site.Address
	if site.Location.Lat != 0 && site.Location.Lng != 0 {
		bsonUpdate["location"] = site.Location
	}
	bsonUpdate["contacts"] = site.Contacts
	bsonUpdate["phone"] = site.Phone
	if site.WorkerArray != nil {
		bsonUpdate["workers"] = site.WorkerArray
	}
	bsonUpdate["wdbegin"] = site.WorkDayBegin
	bsonUpdate["wdend"] = site.WorkDayEnd
	bsonUpdate["wtbegin"] = site.WorkTimeBegin
	bsonUpdate["wtend"] = site.WorkTimeEnd
	bsonUpdate["public"] = site.Public
	bsonUpdate["level"] = site.Level
	bsonUpdate["remark"] = site.Remark

	oid := bson.ObjectIdHex(site.Id)
	err := c.Update(bson.M{"_id": oid}, bson.M{"$set": bsonUpdate})

	return err
}

func (p *DBOperation) maintenanceSiteRemove(id string) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionMaintenanceSites)
	oid := bson.ObjectIdHex(id)
	return c.Remove(bson.M{"_id": oid})
}

type MaintainSiteNearT struct {
	Oid      bson.ObjectId `bson:"_id" json:"-"`
	Id       string        `bson:"-" json:"id"`
	Name     string        `bson:"name" json:"name"`
	Address  string        `bson:"address" json:"address"`
	Location struct {
		Lng float64 `bson:"lng" json:"lng" `
		Lat float64 `bson:"lat" json:"lat"`
	} `bson:"location" json:"location"`
	Distance int `json:"distance"`
}

func (p *DBOperation) maintenanceSiteNear(cid int, tid string, lng, lat float64, radius, count int) []MaintainSiteNearT {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionMaintenanceSites)
	var res []MaintainSiteNearT
	var g gps.GPS

	bsonQuery := bson.M{}
	if cid != 0 {
		bsonQuery["cid"] = cid
	}
	if tid != "" {
		bsonQuery["tid"] = tid
	}
	bsonQuery["location"] = bson.M{"$near": bson.M{"$geometry": bson.M{"type": "Point", "coordinates": []float64{lng, lat}}, "$maxDistance": radius}}
	bsonSelect := bson.M{"_id": 1, "name": 1, "address": 1, "location": 1}
	err := c.Find(bsonQuery).Select(bsonSelect).Limit(count).All(&res)
	if err != nil {
		res = make([]MaintainSiteNearT, 0)
	} else {
		for i := 0; i < len(res); i++ {
			res[i].Id = res[i].Oid.Hex()
			res[i].Distance = int(g.Distance(lat, lng, res[i].Location.Lat, res[i].Location.Lng) * 1000)
		}
	}

	return res
}

type TireStatusCountT struct {
	NewTire     int `json:"newtire"`
	ReuseTire   int `json:"reusetire"`
	RenewTire   int `json:"renewtire"`
	ScraptTire  int `json:"scraptire"`
	NeedFixTire int `json:"needfixtire"`
}
type WarehouseT struct {
	Cid     int              `bson:"cid" json:"cid"`
	Tid     string           `bson:"tid" json:"tid"`
	Team    string           `json:"team"`
	Wid     int64            `bson:"wid" json:"wid"`
	Name    string           `bson:"name" json:"name"`
	Address string           `bson:"address" json:"address"`
	Manager string           `bson:"manager" json:"manager"`
	Phone   string           `bson:"phone" json:"phone"`
	Counts  TireStatusCountT `json:"count"`
}

func (p *DBOperation) warehouseList(cid int, tid, name, address string, page int) (int, []WarehouseT, error) {
	s := p.session.Copy()
	defer s.Close()

	var res []WarehouseT
	c := s.DB(p.dbName).C(CollectionWarehouses)
	bsonQuery := bson.M{}
	if cid != 0 {
		bsonQuery["cid"] = cid
	}
	if tid != "" {
		tids := p.getTeamChilden(tid)
		bsonQuery["tid"] = bson.M{"$in": tids}
	}

	if name != "" && address != "" {
		bsonQuery["$or"] = []bson.M{{"name": bson.RegEx{Pattern: name, Options: "im"}},
			{"address": bson.RegEx{Pattern: address, Options: "im"}}}
	} else if name != "" {
		bsonQuery["name"] = bson.RegEx{Pattern: name, Options: "im"}
	} else if address != "" {
		bsonQuery["address"] = bson.RegEx{Pattern: address, Options: "im"}
	}

	iCount, err := c.Find(bsonQuery).Count()
	if err != nil || iCount == 0 {
		return 0, nil, nil
	}

	if page == -1 {
		err = c.Find(bsonQuery).All(&res)
	} else {
		err = c.Find(bsonQuery).Skip(page * 20).Limit(20).All(&res)
	}
	if err == nil {
		for i := 0; i < len(res); i++ {
			if res[i].Tid != "" {
				res[i].Team = p.getTeamName(res[i].Tid)
			} else {
				res[i].Team = p.getCompanyName(res[i].Cid)
			}

			//检查仓储
			res[i].Counts = p.warehouseTireCount(res[i].Wid)
		}
	}
	return iCount, res, err
}

func (p *DBOperation) warehouseTireCount(wid int64) TireStatusCountT {
	var tsc TireStatusCountT

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTires)
	pipeline := []bson.M{
		{"$match": bson.M{"wid": wid}},
		{"$group": bson.M{"_id": "$status", "num": bson.M{"$sum": 1}}},
	}

	var res []struct {
		ID  int `bson:"_id"`
		Num int `bson:"num"`
	}

	err := c.Pipe(pipeline).All(&res)
	if err == nil {
		for _, v := range res {
			switch v.ID {
			case 0:
				tsc.NewTire = v.Num
			case 1:
				tsc.ReuseTire = v.Num
			case 2:
				tsc.RenewTire = v.Num
			case 3:
				tsc.ScraptTire = v.Num
			case 4:
				tsc.NeedFixTire = v.Num
			}
		}
	}

	return tsc
}

func (p *DBOperation) warehouseAdd(cid int, tid, name, address, manager, phone string) (int64, error) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionWarehouses)
	var res interface{}

	err := c.Find(bson.M{"name": name}).Select(bson.M{"_id": 1}).One(&res)
	if err == nil {
		err = errors.New("已经存在同名的仓库")
		return 0, err
	}

	wid := time.Now().Unix()
	wh := bson.M{"cid": cid, "tid": tid, "wid": wid, "name": name, "address": address, "manager": manager, "phone": phone}
	c.Insert(wh)

	return wid, nil
}

func (p *DBOperation) warehouseEdit(wid, cid int, tid, name, address, manager, phone string) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionWarehouses)
	var res interface{}

	err := c.Find(bson.M{"wid": wid}).Select(bson.M{"_id": 1}).One(&res)
	if err != nil {
		err = errors.New("不存在此仓库")
		return err
	}

	wh := bson.M{"cid": cid, "tid": tid, "wid": wid, "name": name, "address": address, "manager": manager, "phone": phone}
	c.Update(bson.M{"wid": wid}, bson.M{"$set": wh})

	return nil
}

func (p *DBOperation) warehouseDelete(wid int) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionWarehouses)
	c.Remove(bson.M{"wid": wid})
}

func (p *DBOperation) mileageSensor(sid string) float64 {
	s := p.session.Copy()
	defer s.Close()

	var res map[string]float64
	c := s.DB(p.dbName).C(CollectionSensors)
	err := c.Find(bson.M{"sid": sid}).Select(bson.M{"_id": 0, "ma": 1}).One(&res)
	if err != nil {
		return 0
	}
	return res["ma"]
}

type MileagesT struct {
	ID      map[string]int `bson:"_id" json:"-"`
	Date    int            `json:"date"`
	Mileage float32        `json:"mileage"`
}

type MileageStatisticsT struct {
	Type     int         `json:"type"`
	Mileages []MileagesT `json:"mileages"`
}

func (p *DBOperation) mileageStatistics(cid int, tid string, rid string, year int, month int) (*MileageStatisticsT, error) {
	s := p.session.Copy()
	defer s.Close()

	var ms MileageStatisticsT
	var err error

	if year == 0 && month == 0 {
		ms.Type = 1
	} else if year != 0 && month == 0 {
		ms.Type = 2
	} else if year != 0 && month != 0 {
		ms.Type = 3
	} else {
		err = errors.New("参数不正确")
		return nil, err
	}

	bsonMatch := bson.M{}
	bsonGroup := bson.M{}
	bsonSort := bson.M{"_id.date": 1}
	var rids []string

	if rid != "" {
		rids = []string{rid}
	} else if tid != "" {
		rids = p.teamReceivers(tid, "")
	} else if cid != 0 {
		rids = p.companyReceivers(cid, "")
	}

	if rids != nil {
		bsonMatch["rid"] = bson.M{"$in": rids}
	}

	switch ms.Type {
	case 1:
		bsonGroup["_id"] = bson.M{"date": "$y"}
	case 2:
		bsonMatch["y"] = year
		bsonGroup["_id"] = bson.M{"date": "$m"}
	case 3:
		bsonMatch["y"] = year
		bsonMatch["m"] = month
		bsonGroup["_id"] = bson.M{"date": "$d"}
	}
	bsonGroup["mileage"] = bson.M{"$sum": "$ma"}

	c := s.DB(p.dbName).C(CollectionMileageStatistics)
	pipeline := []bson.M{
		{"$match": bsonMatch},
		{"$group": bsonGroup},
		{"$sort": bsonSort},
	}
	err = c.Pipe(pipeline).All(&(ms.Mileages))
	if err != nil {
		return nil, err
	}

	for i := 0; i < len(ms.Mileages); i++ {
		ms.Mileages[i].Date = ms.Mileages[i].ID["date"]
	}

	return &ms, nil
}

type MileageDetailT struct {
	Rid          string `json:"rid" bson:"rid"`
	Date         int    `json:"date"`
	WorkBegin    int    `json:"workbegin"`
	WorkEnd      int    `json:"workend"`
	WorkDuration string `json:"wrokduration"`
	Team         string `json:"team"`
	Plate        string `json:"plate"`
	Driver       string `json:"driver"`
	Mileage      int    `json:"mileage" bson:"ma"`
}

func (p *DBOperation) reportMileage(userid string, cid int, tid string, rid string, beginDate int, endDate int, page int) (int,
	[]MileageDetailT, error) {
	const CountPerPage int = 10 //每次返回10条

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionMileageStatistics)
	var res []MileageDetailT
	var rids []string
	var total int
	// userType := p.userType(userid)

	bsonDates := make([]bson.M, 0)
	bsonDates = append(bsonDates, bson.M{"date": bson.M{"$gte": beginDate}})
	bsonDates = append(bsonDates, bson.M{"date": bson.M{"$lte": endDate}})
	bsonQuery := bson.M{} //"rid": bson.M{"$in": rids}, "$and": bsonDates}
	// if userType != UserTypeSystemUser {
	// 	if tid != "" {
	// 		rids = p.teamReceivers(tid, rid)
	// 	} else {
	// 		rids = p.companyReceivers(cid, rid)
	// 	}

	// 	if len(rids) == 0 {
	// 		return 0, nil, nil
	// 	}
	// 	bsonQuery["rid"] = bson.M{"$in": rids}
	// } else {
	// 	bFull := false
	// 	if tid != "" {
	// 		rids = p.teamReceivers(tid, rid)
	// 	} else if cid != 0 {
	// 		rids = p.companyReceivers(cid, rid)
	// 	} else {
	// 		if rid != "" {
	// 			rids = p.fuzzyQueryRid(rid)
	// 		} else {
	// 			bFull = true
	// 		}
	// 	}

	// 	bsonQuery["rid"] = bson.M{"$exists": 1}
	// }
	rids = p.userReceiversEx(userid, cid, tid, rid)
	if len(rids) == 0 {
		return 0, nil, nil
	}

	bsonQuery["rid"] = bson.M{"$in": rids}
	bsonQuery["$and"] = bsonDates

	total, _ = c.Find(bsonQuery).Count()
	if total == 0 {
		return 0, nil, nil
	}

	query := c.Find(bsonQuery).Select(bson.M{"_id": 0, "rid": 1, "date": 1, "ma": 1}).Sort("date")
	if page >= 0 {
		query = query.Skip(page * CountPerPage).Limit(CountPerPage)
	}
	err := query.All(&res)

	if err != nil {
		return 0, nil, err
	}

	for i := 0; i < len(res); i++ {
		res[i].Team, res[i].Driver, res[i].Plate, _, _, _ = p.receiverTeamAndPlateNo(res[i].Rid)
		res[i].WorkDuration = "" // fmt.Sprintf("%.2f", hh)
	}

	return total, res, nil
}

type TReportWarningT struct {
	Date        int     `bson:"date" json:"date"`
	Time        int     `bson:"time" json:"time"`
	Team        string  `json:"team"`
	Plate       string  `json:"plate"`
	Driver      string  `json:"driver"`
	Rid         string  `bson:"rid" json:"rid"`
	Sid         string  `bson:"sid" json:"sid"`
	CardId      int     `bson:"cardid" json:"cardid"`
	SN          int     `bson:"sn" json:"sn"`
	Presure     float32 `bson:"pres" json:"presure"`
	Temperature int     `bson:"temp" json:"temperature"`
	WarnType    int     `bson:"wt" json:"warntype"`
	Status      int     `bson:"stat" json:"status"`
}

func (p *DBOperation) reportWarning(userid string, cid int, tid string, rid string, beginDate int, endDate int, warnType int,
	repeat int, page int) (int, []TReportWarningT, error) {

	const CountPerPage int = 10 //每次返回10条

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireWarnings)
	// userType := p.userType(userid)

	bsonDates := make([]bson.M, 0)
	bsonDates = append(bsonDates, bson.M{"date": bson.M{"$gte": beginDate}})
	bsonDates = append(bsonDates, bson.M{"date": bson.M{"$lte": endDate}})
	bsonQuery := bson.M{} //"rid": bson.M{"$in": rids}, "$and": bsonDates}
	rids := p.userReceiversEx(userid, cid, tid, rid)
	if len(rids) == 0 {
		return 0, nil, nil
	}
	bsonQuery["rid"] = bson.M{"$in": rids}
	// if userType != UserTypeSystemUser {
	// 	var rids []string
	// 	if tid != "" {
	// 		rids = p.teamReceivers(tid, rid)
	// 	} else {
	// 		rids = p.companyReceivers(cid, rid)
	// 	}

	// 	if len(rids) == 0 {
	// 		return 0, nil, nil
	// 	}
	// 	bsonQuery["rid"] = bson.M{"$in": rids}
	// }
	if warnType != 0 {
		bsonQuery["wt"] = warnType
	}
	if repeat == 1 {
		bsonQuery["stat"] = bson.M{"$ne": -1}
	}
	bsonQuery["$and"] = bsonDates

	total, err := c.Find(bsonQuery).Count()
	if err != nil {
		return 0, nil, err
	}
	if total == 0 {
		return 0, nil, nil
	}

	var res []TReportWarningT

	query := c.Find(bsonQuery).Select(bson.M{"_id": 0, "date": 1, "time": 1, "rid": 1, "sid": 1, "cardid": 1, "sn": 1,
		"pres": 1, "temp": 1, "wt": 1, "stat": 1}).Sort("_id")
	if page >= 0 {
		query = query.Skip(page * CountPerPage).Limit(CountPerPage)
	}
	err = query.All(&res)
	if err != nil {
		return 0, nil, err
	}

	for i := 0; i < len(res); i++ {
		res[i].Team, res[i].Driver, res[i].Plate, _, _, _ = p.receiverTeamAndPlateNo(res[i].Rid)
	}

	return total, res, nil
}

type TReportWarningStatisticsT struct {
	Date      int     `bson:"d" json:"date"`
	BeginTime int     `bson:"st" json:"begintime"`
	EndTime   int     `bson:"et" json:"endtime"`
	Duration  int     `bson:"lt" json:"duration"`
	Team      string  `json:"team"`
	Plate     string  `json:"plate"`
	Driver    string  `json:"driver"`
	Rid       string  `bson:"rid" json:"rid"`
	Sid       string  `bson:"sid" json:"sid"`
	CardId    int     `bson:"cardid" json:"cardid"`
	SN        int     `bson:"sn" json:"sn"`
	Mileage   float32 `bson:"ma" json:"mileage"`
	Count     int     `bson:"count" json:"count"`
	WarnType  int     `bson:"wt" json:"warntype"`
}

func (p *DBOperation) reportAbnormalOperation(userid string, cid int, tid string, rid string, beginDate int, endDate int, warnType int,
	page int) (int, []TReportWarningStatisticsT, error) {

	const CountPerPage int = 10 //每次返回10条

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireWarningStatistics)
	userType := p.userType(userid)

	bsonDates := make([]bson.M, 0)
	bsonDates = append(bsonDates, bson.M{"d": bson.M{"$gte": beginDate}})
	bsonDates = append(bsonDates, bson.M{"d": bson.M{"$lte": endDate}})
	bsonQuery := bson.M{} //"rid": bson.M{"$in": rids}, "$and": bsonDates}

	var rids []string

	if tid != "" {
		rids = p.teamReceivers(tid, rid)
	} else {
		if userType == UserTypeSystemUser {
			if cid != 0 {
				rids = p.companyReceivers(cid, rid)
			}
		} else {
			rids = p.companyReceivers(cid, rid)
		}
	}

	if len(rids) == 0 && userType != UserTypeSystemUser {
		return 0, nil, nil
	}
	if len(rids) > 0 {
		bsonQuery["rid"] = bson.M{"$in": rids}
	}
	// }
	if warnType != 0 {
		bsonQuery["wt"] = warnType
	}

	bsonQuery["$and"] = bsonDates

	total, err := c.Find(bsonQuery).Count()
	if err != nil {
		return 0, nil, err
	}
	if total == 0 {
		return 0, nil, nil
	}

	var res []TReportWarningStatisticsT

	query := c.Find(bsonQuery).Select(bson.M{"_id": 0}).Sort("_id")
	if page >= 0 {
		query = query.Skip(page * CountPerPage).Limit(CountPerPage)
	}
	err = query.All(&res)
	if err != nil {
		return 0, nil, err
	}

	const SecondsOfDay int = 24 * 60 * 60
	for i := 0; i < len(res); i++ {
		if res[i].Duration < 0 {
			res[i].Duration += SecondsOfDay
		}
		res[i].Team, res[i].Driver, res[i].Plate, _, _, _ = p.receiverTeamAndPlateNo(res[i].Rid)
	}

	return total, res, nil
}

func (p *DBOperation) userType(userid string) int {
	if !bson.IsObjectIdHex(userid) {
		return -1
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCustomers)
	var res map[string]int
	_id := bson.ObjectIdHex(userid)

	err := c.Find(bson.M{"_id": _id}).Select(bson.M{"_id": 0, "utype": 1}).One(&res)
	if err != nil {
		return -1
	}
	return res["utype"]
}

type CompanyT struct {
	Cid     int    `bson:"cid" json:"cid"`
	Name    string `bson:"name" json:"name"`
	Manager string `bson:"manager" json:"manager"`
	Phone   string `bson:"phone" json:"phone"`
	EMail   string `bson:"email" json:"email"`
	Stat    int    `bson:"stat" json:"stat"`
	Logo    string `bson:"logo" json:"logo"`
	//Tid     string `json:"tid"`
}

func (p *DBOperation) companyList() []CompanyT {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCompanies)
	var res []CompanyT

	err := c.Find(bson.M{"cid": bson.M{"$exists": 1}}).Sort("name").All(&res)
	if err != nil {
		res = make([]CompanyT, 0)
	}
	return res
}

func (p *DBOperation) userConcernedTeam(userid string) map[string]interface{} {
	teams := map[string]interface{}{"name": "关注车队", "cid": -1, "tid": "", "teams": []map[string]interface{}{}}

	if !bson.IsObjectIdHex(userid) {
		return teams
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCustomers)
	var res ConcernedTeamDB

	_id := bson.ObjectIdHex(userid)
	err := c.Find(bson.M{"_id": _id}).Select(bson.M{"_id": 0, "alert": 1}).One(&res)
	if err == nil {
		concerneds := make([]map[string]interface{}, 0)

		for _, v := range res.Alert.Cids {
			concerned := map[string]interface{}{"cid": v, "name": p.getCompanyName(v), "tid": "", "teams": []map[string]interface{}{}}
			concerneds = append(concerneds, concerned)
		}
		var cid int
		var name string

		for _, v := range res.Alert.Tids {
			cid, name = p.getTeamCidAndName(v)
			if cid != 0 && name != "" {
				concerned := map[string]interface{}{"cid": cid, "name": name, "tid": v, "teams": []map[string]interface{}{}}
				concerneds = append(concerneds, concerned)
			}
		}

		teams["teams"] = concerneds
	}
	return teams
}

func (p *DBOperation) companyAdd(name, manager, phone, email, logo string) (int, error) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCompanies)
	var res map[string]int

	err := c.Find(bson.M{"name": name}).Select(bson.M{"_id": 1}).One(nil)
	if err == nil {
		err := errors.New("已经存在同名的公司")
		return 0, err
	}

	c.Find(nil).Sort("-cid").Select(bson.M{"_id": 0, "cid": 1}).Limit(1).One(&res)

	company := CompanyT{Name: name, Manager: manager, Phone: phone, EMail: email, Stat: 0, Logo: logo}
	company.Cid = res["cid"] + 1

	err = c.Insert(company)
	if err != nil {
		return 0, err
	}
	return company.Cid, nil
}

func (p *DBOperation) companyModify(cid int, name, manager, phone, email, logo string) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCompanies)

	if name != "" {
		err := c.Find(bson.M{"cid": bson.M{"$ne": cid}, "name": name}).Select(bson.M{"_id": 1}).One(nil)
		if err == nil {
			return errors.New("已经存在同名的公司")
		}
	}

	return c.Update(bson.M{"cid": cid}, bson.M{"$set": bson.M{"name": name, "manager": manager,
		"phone": phone, "email": email, "logo": logo}})
}

func (p *DBOperation) companyDelete(cid int) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCompanies)

	return c.Update(bson.M{"cid": cid}, bson.M{"$set": bson.M{"cid_deleted": cid}, "$unset": bson.M{"cid": 1}})
}

type CompanyStateT struct {
	Online        int `json:"online"`
	Offline       int `json:"offline"`
	Normal        int `json:"normal"`
	Abnormal      int `json:"abnormal"`
	SensorOnline  int `json:"sensoronline"`
	SensorOffline int `json:"sensoroffline"`
}

type CompanyAlertT struct {
	Jlq int `json:"jlq"`
	Mlq int `json:"mlq"`
	Gw  int `json:"gw"`
	Gy  int `json:"gy"`
	Dy  int `json:"dy"`
	Sl  int `json:"sl"`
	Dyd int `json:"dyd"`
}

type CompanyBriefT struct {
	Cid          int           `json:"cid"`
	Tid          string        `json:"tid"`
	Name         string        `json:"name"`
	DeviceCount  int           `json:"devicecount"`
	VehicleCount int           `json:"vehiclecount"`
	AlertCount   int           `json:"alertcount"`
	Mileage      int           `json:"mileage"`
	Cost         float64       `json:"cost"`
	State        CompanyStateT `json:"state"`
	Alert        CompanyAlertT `json:"alert"`
}

func (p *DBOperation) companyBrief(cid int, tid string, d int) (*CompanyBriefT, error) {
	var cb CompanyBriefT
	td := today(0)

	cb.Cid = cid
	cb.Tid = tid
	var alertCounts []AlertCountT
	t := TimeStampToInt(int(time.Now().Unix() - SensorOfflineInterval))

	rids, err := p.getReceiversOfTeam(cid, tid)
	if err != nil {
		return &cb, err
	}

	if tid == "" {
		if cid == 0 {
			cb.Name = "所有车队"
		} else {
			cb.Name = p.getCompanyName(cid)
		}
		if len(rids) > 0 {
			cb.DeviceCount = len(rids)
		} else {
			cb.DeviceCount = p.companyReceiverCount(cid)
		}
		cb.VehicleCount = p.companyVehicleCount2(cid)
		cb.AlertCount = p.receiversAlertCount(rids, td)
		cb.Mileage = p.receiversMileage(rids, today(-1))
		cb.Cost = p.teamCost(cid, tid, today(0))
		cb.State.Online, cb.State.Offline = p.receiversOnlineStatus(rids)
		cb.State.Normal, cb.State.Abnormal = p.receiversNormalStatus(rids)
		cb.State.SensorOnline, cb.State.SensorOffline = p.companySensorOnline(cid, t)

		alertCounts = p.receiversAlertDetail(rids, td)
	} else {
		cb.Name = p.getTeamName(tid)
		if len(rids) > 0 {
			cb.DeviceCount = len(rids)
		} else {
			cb.DeviceCount = p.teamDeviceCount(tid)
		}
		cb.VehicleCount = p.teamVehicleCount(tid)
		cb.AlertCount = p.receiversAlertCount(rids, td)
		cb.Mileage = p.receiversMileage(rids, today(-1))
		cb.Cost = p.teamCost(cid, tid, today(0))
		cb.State.Online, cb.State.Offline = p.receiversOnlineStatus(rids)
		cb.State.Normal, cb.State.Abnormal = p.receiversNormalStatus(rids)
		cb.State.SensorOnline, cb.State.SensorOffline = p.teamSensorOnline(tid, t)

		alertCounts = p.receiversAlertDetail(rids, td)

	}
	for _, v := range alertCounts {
		switch v.ID {
		case 1:
			cb.Alert.Jlq = v.Count
		case 2:
			cb.Alert.Mlq = v.Count
		case 3:
			cb.Alert.Gw = v.Count
		case 4:
			cb.Alert.Gy = v.Count
		case 5:
			cb.Alert.Dy = v.Count
		case 6:
			cb.Alert.Sl = v.Count
		case 7:
			cb.Alert.Dyd = v.Count
		}
	}

	return &cb, nil
}

type TeamBriefT struct {
	Cid          int    `bson:"cid" json:"cid"`
	Tid          string `json:"tid" bson:"tid"`
	Name         string `json:"name" bson:"name"`
	Manager      string `json:"manager" bson:"manager"`
	Phone        string `json:"phone" bson:"phone"`
	Workflow     string `json:"workflow" bson:"workflow"`
	VehicleCount int    `json:"vehiclecount"`
}

func (p *DBOperation) companySubTeam(cid int, tid string) ([]TeamBriefT, error) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTeams)
	bsonQuery := bson.M{"cid": cid, "pid": tid}
	var res []TeamBriefT
	// ret := make([]TeamBriefT, 0)

	err := c.Find(bsonQuery).Select(bson.M{"_id": 0, "cid": 1, "pid": 1, "tid": 1, "name": 1,
		"manager": 1, "phone": 1, "workflow": 1}).Sort("name").All(&res)
	if err != nil {
		return nil, err
	}

	c = s.DB(p.dbName).C(CollectionOrganizationProperties)
	for i := 0; i < len(res); i++ {
		bsonQuery = bson.M{"tid": res[i].Tid, "vid": bson.M{"$exists": 1}}
		res[i].VehicleCount, _ = c.Find(bsonQuery).Count()

	}

	return res, nil
}

func (p *DBOperation) getCompanyTires(userid string, cid int, tid string, tno string, page int) (total int, tnos []string, err error) {
	const CountPerPage int = 10 //每页条数

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTires)
	bsonQuery := bson.M{} //"cid": cid}

	if tid != "" {
		bsonQuery["tid"] = tid
	} else {
		if cid != 0 {
			bsonQuery["cid"] = cid
		}
	}
	if tno != "" {
		bsonQuery["tno"] = bson.RegEx{Pattern: tno, Options: "im"}
	}

	// userType := p.userType(userid)
	// if userType != UserTypeSystemUser {
	// 	if tid != "" {
	// 		bsonQuery["tid"] = tid
	// 	} else {
	// 		bsonQuery["cid"] = cid
	// 	}
	// 	if tno != "" {
	// 		bsonQuery["tno"] = bson.RegEx{Pattern: tno, Options: "im"}
	// 	}
	// }

	total, err = c.Find(bsonQuery).Count()

	if err == nil && total > 0 {
		var res []map[string]string
		err = c.Find(bsonQuery).Select(bson.M{"_id": 0, "tno": 1}).Skip(CountPerPage * page).Limit(CountPerPage).All(&res)
		if err == nil {
			tnos = make([]string, 0, len(res))
			for _, v := range res {
				tnos = append(tnos, v["tno"])
			}
		}
	}
	return
}

type TireListT struct {
	Company     string      `json:"company"`
	Team        string      `json:"team"`
	Tno         string      `json:"tno"`
	Mid         string      `json:"mid"`
	Bt          int64       `json:"bt"`
	Rid         string      `json:"rid"`
	Sid         string      `json:"sid"`
	CardId      int         `json:"cardid"`
	Sn          int         `json:"sn"`
	Vid         string      `json:"vid"`
	Plate       string      `json:"plate"`
	Driver      string      `json:"driver"`
	DriverPhone string      `json:"driverphone"`
	Mileage     float64     `json:"mileage"`
	Duration    int         `json:"duration"`
	Operator    string      `json:"operator"`    //安装人员
	OperateTime int64       `json:"operatetime"` //安装时间
	Depths      interface{} `json:"depths"`      //花纹深度
}

type RelationsT struct {
	Rid    string `bson:"rid"`
	Sid    string `bson:"sid"`
	CardId int    `bson:"cardid"`
	Sn     int    `bson:"sn"`
}

type VehiclesT struct {
	Vid         string `bson:"vid"`
	Driver      string `bson:"driver"`
	DriverPhone string `bson:"driverphone"`
	Plate       string `bson:"plate"`
	Tid         string `bson:"tid"`
}

type TireDBT struct {
	Companies   []map[string]string `bson:"companies"`
	Tno         string              `bson:"tno"`
	Mid         string              `bson:"mid"`
	Bt          int64               `bson:"bt"`
	Relations   []RelationsT        `bson:"relations"`
	Vehicles    []VehiclesT         `bson:"vehicles"`
	Mileage     float64             `bson:"ma"`
	Duration    int                 `json:"duration"`
	Operator    string              `bson:"operator"` //安装人员
	OperateTime int64               `bson:"ot"`       //安装时间
	Depths      interface{}         `bson:"cpdepths"` //花纹深度
}

func (p *DBOperation) TireDBToTireList(data *TireDBT, tireList *TireListT) {
	if len(data.Companies) > 0 {
		tireList.Company = data.Companies[0]["name"]
	}
	if len(data.Vehicles) > 0 {
		v := &(data.Vehicles[0])
		tid := v.Tid
		if tid != "" {
			tireList.Team = p.getTeamName(tid)
		}
		tireList.Vid = v.Vid
		tireList.Plate = v.Plate
		tireList.Driver = v.Driver
		tireList.DriverPhone = v.DriverPhone
	}
	tireList.Tno = data.Tno
	tireList.Mid = data.Mid
	tireList.Bt = data.Bt
	if len(data.Relations) > 0 {
		v := &(data.Relations[0])
		tireList.Rid = v.Rid
		tireList.Sid = v.Sid
		tireList.CardId = v.CardId
		tireList.Sn = v.Sn
	}
	tireList.Mileage = data.Mileage
	tireList.Duration = 0 //暂时设置为0
	tireList.Operator = data.Operator
	tireList.OperateTime = data.OperateTime
}

func (p *DBOperation) tireList(userid string, cid int, tid string, tno string, page int) (int, []TireListT) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTires)

	var total int
	var err error
	var tnos []string

	total, tnos, err = p.getCompanyTires(userid, cid, tid, tno, page)
	if err != nil || total == 0 {
		return 0, nil
	}

	pipeline := []bson.M{
		{"$match": bson.M{"tno": bson.M{"$in": tnos}}},
		{"$lookup": bson.M{"from": "relations", "localField": "tno", "foreignField": "tno", "as": "relations"}},
		{"$lookup": bson.M{"from": "receivers", "localField": "relations.rid", "foreignField": "rid", "as": "receivers"}},
		{"$lookup": bson.M{"from": "vehicles", "localField": "receivers.vid", "foreignField": "vid", "as": "vehicles"}},
		{"$lookup": bson.M{"from": "companies", "localField": "vehicles.cid", "foreignField": "cid", "as": "companies"}},
		{"$project": bson.M{"_id": 0, "tno": 1, "mid": 1, "bt": 1, "ma": 1, "cpdepths": 1, "operator": 1, "ot": 1,
			"relations.rid": 1, "relations.sid": 1, "relations.cardid": 1, "relations.sn": 1, "receivers.vid": 1,
			"vehicles.vid": 1, "vehicles.cid": 1, "vehicles.tid": 1, "vehicles.driver": 1, "vehicles.driverphone": 1, "vehicles.plate": 1,
			"companies.name": 1}},
		// bson.M{"$unwind": bson.M{"path": "$relations"}},
		// bson.M{"$unwind": bson.M{"path": "$receivers"}},
		// bson.M{"$unwind": bson.M{"path": "$vehicles"}},
		// bson.M{"$unwind": bson.M{"path": "$companies"}},
	}

	var res []TireDBT
	err = c.Pipe(pipeline).All(&res)
	if err != nil {
		return 0, nil
	}

	ret := make([]TireListT, 0, len(res))
	for _, v := range res {
		t := TireListT{}
		p.TireDBToTireList(&v, &t)
		ret = append(ret, t)
	}

	return total, ret
}

type TireQueryInfoT struct {
	Cid       int       `bson:"cid" json:"cid"`
	Tid       string    `bson:"tid" json:"tid"`
	Tids      []string  `bson:"tids" json:"tids"`
	Team      string    `json:"team"`
	Wid       int64     `bson:"wid" json:"wid"`
	Warehouse string    `json:"warehouse"`
	Tno       string    `json:"tno" bson:"tno"`
	Dot       string    `bson:"dot" json:"dot"`
	RFID      string    `bson:"rfid" json:"rfid"`
	Bid       int       `bson:"bid" json:"bid"`
	Brand     string    `json:"brand"`
	Mid       string    `bson:"mid" json:"mid"`
	Pattern   string    `bson:"pattern" json:"pattern"`
	Cpdepths  []float32 `bson:"cpdepths" json:"-"`
	Pdepth    string    `json:"pdepth"`
	IntoDate  int       `bson:"intodate" json:"intodate"`
	Mileage   float64   `bson:"ma" json:"mileage"`
	Status    int       `bson:"status" json:"status"`
	Reason    string    `bson:"reason" json:"reason"`
}

func (p *DBOperation) tireQuery(cid int, tid string, wid, bid int, mid, tno, sensor, dot, rfid string, status, instock,
	threshold1, threshold2, page int) (int, []TireQueryInfoT) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTires)

	bsonQuery := bson.M{}
	if cid != 0 {
		bsonQuery["cid"] = cid
	}
	if tid != "" {
		bsonQuery["tids"] = tid
	}
	if wid != 0 {
		bsonQuery["wid"] = wid
	}
	if bid != 0 {
		bsonQuery["bid"] = bid
	}
	if mid != "" {
		bsonQuery["mid"] = mid
	}
	if tno != "" {
		bsonQuery["tno"] = bson.RegEx{Pattern: tno, Options: "im"}
	}
	if sensor != "" {
		bsonQuery["sensor"] = sensor
	}
	if dot != "" {
		bsonQuery["dot"] = bson.RegEx{Pattern: dot, Options: "im"}
	}
	if rfid != "" {
		bsonQuery["rfid"] = bson.RegEx{Pattern: rfid, Options: "im"}
	}

	if status >= 0 {
		bsonQuery["status"] = status
	}

	if instock == 0 {
		bsonQuery["wid"] = 0
	} else if instock == 1 {
		bsonQuery["wid"] = bson.M{"$gt": 0}
	}

	if threshold1 > 0 {
		bsonQuery["cpdepths"] = bson.M{"$lte": threshold1}
	}

	var iCount int
	var err error

	iCount, err = c.Find(bsonQuery).Count()
	if err != nil || iCount == 0 {
		return 0, nil
	}

	var res []TireQueryInfoT
	err = c.Find(bsonQuery).
		Select(bson.M{"_id": 0, "cid": 1, "tid": 1, "tids": 1, "wid": 1, "bid": 1, "mid": 1, "tno": 1, "dot": 1, "rfid": 1, "status": 1,
			"pattern": 1, "intodate": 1, "ma": 1, "cpdepths": 1, "reason": 1}).
		Skip(page * 10).
		Limit(10).
		All(&res)

	if err != nil || res == nil {
		return 0, nil
	}

	var iLen int
	var aDepths []string
	var tempTid string

	for i := 0; i < len(res); i++ {
		tempTid = ""
		if res[i].Tid != "" {
			tempTid = res[i].Tid
		} else {
			iLen = len(res[i].Tids)
			if iLen > 0 {
				tempTid = res[i].Tids[iLen-1]
				res[i].Tid = tempTid
			}
		}

		if tempTid != "" { //res[i].Tid != "" {
			res[i].Team = p.getTeamName(tempTid) //res[i].Tid)
		} else {
			res[i].Team = p.getCompanyName(res[i].Cid)
		}

		if res[i].Wid != 0 {
			res[i].Warehouse = p.getWarehouseName(res[i].Wid)
		}

		if res[i].Bid != 0 {
			res[i].Brand = p.getTireBrandName(cid, res[i].Bid)
		}

		iLen = len(res[i].Cpdepths)
		if iLen > 0 {
			aDepths = make([]string, iLen)
			for j := 0; j < iLen; j++ {
				aDepths[j] = fmt.Sprintf("%.02f", res[i].Cpdepths[j])
			}
			res[i].Pdepth = strings.Join(aDepths, ",")
		}

		// if res[i].Bid != 0 && res[i].Mid != "" {
		// 	res[i].Pattern = p.getTirePattern(res[i].Bid, res[i].Mid)
		// }
	}

	return iCount, res
}

func (p *DBOperation) tireByRFID(cid int, rfid string) string {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTires)
	var res map[string]string

	bsonQuery := bson.M{}
	if cid != 0 {
		bsonQuery["cid"] = cid
	}
	bsonQuery["rfid"] = rfid

	err := c.Find(bsonQuery).Select(bson.M{"_id": 0, "tno": 1}).One(&res)
	if err == nil {
		return res["tno"]
	}
	return ""
}

type TireActionT struct {
	Cid      int       `bson:"cid"`
	Tid      string    `bson:"tid"`
	Wid      int       `bson:"wid"`
	Rid      string    `bson:"rid"`
	Vid      string    `bson:"vid"`
	Tno      string    `bson:"tno"`
	T        int64     `bson:"t"`
	Date     int       `bson:"date"`
	Time     int       `bson:"time"`
	Action   int       `bson:"action"`
	Cpdepths []float32 `bson:"cpdepths"`
	Mileage  int       `bson:"ma"`
	Status   int       `bson:"status"`
	Reason   string    `bson:"reason"`
	Operator string    `bson:"operator"`
}

func (p *DBOperation) saveTireAction(ta *TireActionT) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireActions)

	if ta.Mileage == 0 || ta.Status == 0 || len(ta.Cpdepths) == 0 {
		var ti TireInfoT
		p.getTireInfo(ta.Cid, ta.Tno, &ti)
		if ta.Mileage == 0 {
			ta.Mileage = int(ti.Mileage)
		}
		if ta.Status == 0 {
			ta.Status = ti.Status
		}
		if len(ta.Cpdepths) == 0 {
			ta.Cpdepths = ti.Depth
		}
	}

	c.Insert(ta)
}

func (p *DBOperation) tireAdd(userid string, cid int, tid string, wid, bid int, mid, pattern, tno, dot, rfid, depths string,
	status, intodate int, reason string) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTires)

	err := c.Find(bson.M{"cid": cid, "tno": tno}).Select(bson.M{"_id": 1}).One(nil)
	if err == nil {
		return errors.New("已经存在该轮胎号")
	}

	bsonQuery := bson.M{}
	bsonQuery["tno"] = tno
	bsonQuery["cid"] = cid
	bsonQuery["tid"] = tid
	tids := []string{}
	if tid != "" {
		tids = p.getTeamParents(tid)
	}
	bsonQuery["tids"] = tids //[]string{tid}
	bsonQuery["wid"] = wid
	bsonQuery["bid"] = bid
	bsonQuery["mid"] = mid
	bsonQuery["pattern"] = pattern
	bsonQuery["dot"] = dot
	bsonQuery["rfid"] = rfid
	bsonQuery["status"] = status
	bsonQuery["intodate"] = intodate
	bsonQuery["reason"] = reason

	aCpdepths := make([]float32, 0)
	var fDepth float64

	if depths != "" {
		aPdepths := strings.Split(depths, ",")
		for _, v := range aPdepths {
			fDepth, _ = strconv.ParseFloat(v, 32)
			aCpdepths = append(aCpdepths, float32(fDepth))
		}
	}
	bsonQuery["cpdepths"] = aCpdepths

	c.Insert(bsonQuery)

	ta := TireActionT{Cid: cid, Tid: tid, Wid: wid, Rid: "", Tno: tno, T: time.Now().Unix(), Date: intodate,
		Action: TireActionStockIn, Cpdepths: aCpdepths, Reason: reason, Status: status, Operator: p.userId2User(userid)}
	p.saveTireAction(&ta)

	return nil
}

func (p *DBOperation) tireEdit(userid string, cid int, tid string, wid, bid int, mid, pattern, tno, dot, rfid, depths string,
	status, intodate int, reason string) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTires)

	bsonQuery := bson.M{"cid": cid, "tno": tno}
	err := c.Find(bsonQuery).Select(bson.M{"_id": 1}).One(nil)
	if err != nil {
		return errors.New("不存在该轮胎号")
	}

	tids := []string{}
	if tid != "" {
		tids = p.getTeamParents(tid)
	}
	bsonUpdate := bson.M{}
	bsonUpdate["tid"] = tid
	bsonUpdate["tids"] = tids //[]string{tid}
	bsonUpdate["wid"] = wid
	bsonUpdate["bid"] = bid
	bsonUpdate["mid"] = mid
	bsonUpdate["pattern"] = pattern
	bsonUpdate["dot"] = dot
	bsonUpdate["rfid"] = rfid
	bsonUpdate["status"] = status
	bsonUpdate["intodate"] = intodate
	bsonUpdate["reason"] = reason

	aCpdepths := make([]float32, 0)
	var fDepth float64

	if depths != "" {
		aPdepths := strings.Split(depths, ",")
		for _, v := range aPdepths {
			fDepth, _ = strconv.ParseFloat(v, 32)
			aCpdepths = append(aCpdepths, float32(fDepth))
		}
	}
	bsonUpdate["cpdepths"] = aCpdepths

	c.Update(bsonQuery, bson.M{"$set": bsonUpdate})

	action := TireActionEdit
	if status == TireStatusScrapt {
		action = TireActionScrap
	}
	ta := TireActionT{Cid: cid, Tid: tid, Wid: wid, Rid: "", Tno: tno, T: time.Now().Unix(), Date: intodate,
		Action: action, Cpdepths: aCpdepths, Status: status, Reason: reason, Operator: p.userId2User(userid)}
	p.saveTireAction(&ta)

	return nil
}

func (p *DBOperation) tireDelete(cid int, tno string) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTires)
	err := c.Find(bson.M{"cid": cid, "tno": tno}).Select(bson.M{"_id": 1}).One(nil)
	if err != nil {
		return err
	}
	return c.Remove(bson.M{"cid": cid, "tno": tno})
}

type TireBaseInfoT struct {
	Cid       int       `bson:"cid" json:"-"`
	Tid       string    `bson:"tid" json:"-"`
	Team      string    `json:"team"`
	Wid       int64     `bson:"wid" json:"wid"`
	Warehouse string    `json:"warehouse"`
	Bid       int       `bson:"bid" json:"-"`
	Brand     string    `json:"brand"`
	Mid       string    `bson:"mid" json:"model"`
	Rid       string    `bson:"rid" json:"rid"`
	Vid       string    `json:"vid"`
	BindTime  int64     `bson:"bt" json:"bindtime"`
	Plate     string    `json:"plate"`
	Tno       string    `bson:"tno" json:"tno"`
	Dot       string    `bson:"dot" json:"dot"`
	Rfid      string    `bson:"rfid" json:"rfid"`
	Pattern   string    `bson:"pattern" json:"pattern"`
	Cpdepths  []float32 `bson:"cpdepths" json:"cpdepths"`
	Mileage   int       `bson:"ma" json:"mileage"`
	Sensor    string    `bson:"sensor" json:"sensor"`
	Cardid    int       `json:"cardid"`
	Sn        int       `json:"sn"`
	Status    int       `bson:"status" json:"status"`
}

func (p *DBOperation) tireBaseInfo(cid int, tno string) *TireBaseInfoT {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTires)
	var tbi TireBaseInfoT

	err := c.Find(bson.M{"cid": cid, "tno": tno}).
		Select(bson.M{"_id": 0, "cid": 1, "tid": 1, "wid": 1, "bid": 1, "mid": 1, "rid": 1, "bt": 1, "tno": 1,
			"dot": 1, "rfid": 1, "pattern": 1, "ma": 1, "cpdepths": 1, "status": 1}).
		One(&tbi)

	if err != nil {
		return nil
	}

	if tbi.Tid != "" {
		tbi.Team = p.getTeamName(tbi.Tid)
	} else {
		tbi.Team = p.getCompanyName(tbi.Cid)
	}
	tbi.Warehouse = p.getWarehouseName(tbi.Wid)
	tbi.Brand = p.getTireBrandName(tbi.Cid, tbi.Bid)
	if tbi.Tno != "" {
		tbi.Vid = p.getVehicleByTire(tbi.Tno)
	}
	if tbi.Rid != "" {
		tbi.Plate, _, _, _, _, _ = p.getPlateByRid(tbi.Rid)
	} else if tbi.Vid != "" {
		tbi.Plate, _, _, _, _, _ = p.getPlateByVid(tbi.Vid)
	}
	if tbi.Rid != "" && tbi.Tno != "" {
		tbi.Sensor, tbi.Cardid, tbi.Sn = p.getSensorByRidTno(tbi.Rid, tbi.Tno)
	}

	return &tbi
}

func (p *DBOperation) getVehicleByTire(tno string) string {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionRelations)
	var res map[string]string

	err := c.Find(bson.M{"tno": tno, "vid": bson.M{"$exists": 1}}).Select(bson.M{"_id": 0, "vid": 1}).One(&res)
	if err != nil {
		return ""
	}

	return res["vid"]
}

func (p *DBOperation) getSensorByRidTno(rid, tno string) (string, int, int) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionRelations)
	var res struct {
		Sensor string `bson:"sid"`
		Cardid int    `bson:"cardid"`
		Sn     int    `bson:"sn"`
	}

	err := c.Find(bson.M{"rid": rid, "tno": tno}).Select(bson.M{"_id": 0, "sid": 1, "cardid": 1, "sn": 1}).One(&res)
	if err != nil {
		return "", 0, 0
	}
	return res.Sensor, res.Cardid, res.Sn
}

type TireLifeCircleT struct {
	Cid       int       `bson:"cid" json:"-"`
	Tid       string    `bson:"tid" json:"-"`
	Team      string    `json:"team"`
	Wid       int64     `bson:"wid" json:"-"`
	Warehouse string    `json:"warehouse"`
	Rid       string    `json:"rid" bson:"rid"`
	Date      int       `bson:"date" json:"date"`
	Time      int       `bson:"time" json:"time"`
	Action    int       `bson:"action" json:"action"`
	Cpdepths  []float32 `bson:"cpdepths" json:"cpdepths"`
	Mileage   int       `bson:"ma" json:"mileage"`
	Reason    string    `bson:"reason" json:"reason"`
	Operator  string    `bson:"operator" json:"operator"`
	Status    int       `bson:"status" json:"status"`
}

func (p *DBOperation) tireLifeCircle(cid int, tno string) []TireLifeCircleT {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireActions)
	var res []TireLifeCircleT

	err := c.Find(bson.M{"cid": cid, "tno": tno}).Sort("t").All(&res)
	if err != nil {
		return nil
	}
	for i := 0; i < len(res); i++ {
		if res[i].Tid != "" {
			res[i].Team = p.getTeamName(res[i].Tid)
		} else {
			res[i].Team = p.getCompanyName(res[i].Cid)
		}
		res[i].Warehouse = p.getWarehouseName(res[i].Wid)
	}
	return res
}

func (p *DBOperation) tireMqlStockIn(userid string, si *MqlStockInT) error {
	s := p.session.Copy()
	defer s.Close()

	var err error

	tbid := p.getTireBrandIdByName(si.Cid, si.Brand)
	if tbid == 0 {
		tbid, _ = p.tireBrandAdd(si.Cid, si.Brand)
	}

	var fDepth float64
	fDepth, err = strconv.ParseFloat(si.Depth, 64)
	if err != nil {
		fDepth = 0.0
	}
	p.tireModelAdd(si.Cid, tbid, si.Model, si.Model, si.Pattern, fDepth, 0, 0, 0)

	// tireAdd(userid string, cid int, tid string, wid, bid int, mid, pattern, tno, dot, depths string,
	// 	status, intodate int, reason string)
	var intoDate int = TimeStampToInt(int(time.Now().Unix())) / 1000000
	err = p.tireAdd(userid, si.Cid, si.Tid, si.Wid, tbid, si.Model, si.Pattern, si.Tno, si.Dot, si.Rfid,
		si.Depth, si.Status, intoDate, "米其林扫描入库")

	return err
}

func (p *DBOperation) tireUnload(userid string, cid int, tid string, wid int, rid, vid string, cardid, sn int,
	tno, depths string, status, ma int, reason string) error {
	s := p.session.Copy()
	defer s.Close()

	var err error
	var tids []string

	c := s.DB(p.dbName).C(CollectionTires)

	if cid == 0 {
		if rid != "" {
			cid, tids = p.getCompanyAndTeamByRid(rid)
		} else {
			cid, tids = p.getCompanyAndTeamByVid(vid)
		}
		if len(tids) > 0 {
			tid = tids[len(tids)-1]
		}
	}

	bsonQuery := bson.M{"cid": cid, "tno": tno}
	bsonUpdate := bson.M{"$set": bson.M{"status": status, "wid": wid, "rid": "", "binded": false}}
	err = c.Update(bsonQuery, bsonUpdate)
	if err != nil {
		return err
	}

	aCpdepths := make([]float32, 0)
	var fDepth float64

	if depths != "" {
		aPdepths := strings.Split(depths, ",")
		for _, v := range aPdepths {
			fDepth, _ = strconv.ParseFloat(v, 32)
			aCpdepths = append(aCpdepths, float32(fDepth))
		}
	}
	ta := TireActionT{
		Cid:      cid,
		Tid:      tid,
		Wid:      wid,
		Rid:      rid,
		Tno:      tno,
		T:        time.Now().Unix(),
		Action:   TireActionGetOff,
		Cpdepths: aCpdepths,
		Mileage:  ma,
		Status:   status,
		Reason:   reason,
		Operator: p.userId2User(userid),
	}
	ta.Date, ta.Time = TimeStampToIntDateAndTime(int(ta.T))
	p.saveTireAction(&ta)

	c = s.DB(p.dbName).C(CollectionRelations)
	bsonQuery = bson.M{"cardid": cardid, "sn": sn}
	if rid != "" {
		bsonQuery["rid"] = rid
	}
	if vid != "" {
		bsonQuery["vid"] = vid
	}
	bsonUpdate = bson.M{"$set": bson.M{"tno": ""}}
	err = c.Update(bsonQuery, bsonUpdate)

	return err
}

func (p *DBOperation) TireExchangeTirePosition(rid, vid string, cardid1, sn1 int, tno1 string, cardid2, sn2 int, tno2,
	operator string, opt int) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionRelations)
	var err error

	bsonQuery := bson.M{}
	if rid != "" {
		bsonQuery["rid"] = rid
	} else if vid != "" {
		bsonQuery["vid"] = vid
	} else {
		return errors.New("设备号与车辆号不能同时为空")
	}
	bsonQuery["cardid"] = cardid1
	bsonQuery["sn"] = sn1

	err = c.Update(bsonQuery, bson.M{"$set": bson.M{"tno": tno2}})
	if err == nil {
		bsonQuery["cardid"] = cardid2
		bsonQuery["sn"] = sn2

		err = c.Update(bsonQuery, bson.M{"$set": bson.M{"tno": tno1}})
	}

	return err
}

func (p *DBOperation) tireSetThreshold(userid string, threshold1, threshold2 int) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCustomers)
	oid := bson.ObjectIdHex(userid)
	c.Update(bson.M{"_id": oid}, bson.M{"$set": bson.M{"tpdt1": threshold1, "tpdt2": threshold2}})
}

func (p *DBOperation) tireMaintain(mi *MaintainInfo) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireMaintains)
	c.Insert(mi)

	var sDepth string
	for _, v := range mi.NewTire.Depth {
		sDepth += fmt.Sprintf("%.1f,", v)
	}
	if sDepth != "" {
		sDepth = sDepth[:len(sDepth)-1]
	}
	brandId := p.tireBrandNameToID(mi.Cid, mi.NewTire.Brand)
	p.tireSet(mi.Cid, mi.Tid, mi.Rid, mi.Vid, mi.CardId, mi.Sn, brandId, mi.NewTire.Model, mi.NewTire.Pattern,
		mi.NewTire.TireNo, mi.OldTire.TireNo, mi.NewTire.Dot, mi.NewTire.Mileage, sDepth,
		mi.Operator, int(mi.MaintainTime), 0)
}

type TireMaintainListT struct {
	Id           bson.ObjectId `bson:"_id" json:"id"`
	MaintainTime int64         `bson:"mtime" json:"dt"`
	Position     string        `bson:"position" json:"position"`
	MaintainType int           `bson:"mtype" json:"mtype"`
	Plate        string        `bson:"plate" json:"plate"`
	Team         string        `bson:"team" json:"team"`
}

func (p *DBOperation) tireMaintainList(cid int, tid, vid string, cardid, sn, dateStart, dateEnd, page int) (int, []TireMaintainListT, error) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireMaintains)

	bsonQuery := bson.M{"cid": cid}
	if tid != "" {
		bsonQuery["tid"] = tid
	}
	if vid != "" {
		bsonQuery["vid"] = vid
	}
	if cardid != -1 {
		bsonQuery["cardid"] = cardid
	}
	if sn != -1 {
		bsonQuery["sn"] = sn
	}
	if dateStart != -1 && dateEnd != -1 {
		bsonDate := []bson.M{}
		bsonDate = append(bsonDate, bson.M{"$gte": dateStart})
		bsonDate = append(bsonDate, bson.M{"$lte": dateEnd})
		bsonQuery["$and"] = bsonDate
	}

	var res []TireMaintainListT
	var err error
	var total int

	total, err = c.Find(bsonQuery).Count()
	if err == nil {
		err = c.Find(bsonQuery).
			Select(bson.M{"_id": 1, "mtime": 1, "position": 1, "mtype": 1, "plate": 1, "team": 1}).
			Sort("-mtime").
			Limit(20).
			Skip(page * 20).
			All(&res)
	}

	return total, res, err
}

func (p *DBOperation) tireMaintainDetail(id string) (*MaintainInfo, error) {
	s := p.session.Copy()
	defer s.Close()

	var res MaintainInfo
	c := s.DB(p.dbName).C(CollectionTireMaintains)
	_id := bson.ObjectIdHex(id)
	err := c.Find(bson.M{"_id": _id}).One(&res)
	return &res, err
}

func (p *DBOperation) receiverType(rid string) int {
	s := p.session.Copy()
	defer s.Close()

	var res map[string]int
	c := s.DB(p.dbName).C(CollectionReceivers)
	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "type": 1}).One(&res)
	if err != nil {
		return -1
	}
	return res["type"]
}

func (p *DBOperation) vehicleType(vid string) int {
	s := p.session.Copy()
	defer s.Close()

	var res map[string]int
	c := s.DB(p.dbName).C(CollectionVehicles)
	err := c.Find(bson.M{"vid": vid}).Select(bson.M{"_id": 0, "type": 1}).One(&res)
	if err != nil {
		return -1
	}
	return res["type"]
}

func (p *DBOperation) setReceiverType(rid string, rType int) {
	oldType := p.receiverType(rid)
	//类别不同才需要修改
	if oldType != rType {
		s := p.session.Copy()
		defer s.Close()

		bsonSelector := bson.M{"rid": rid}
		bsonUpdate := bson.M{"$set": bson.M{"type": rType}}

		c := s.DB(p.dbName).C(CollectionReceivers)
		c.Update(bsonSelector, bsonUpdate)
		c = s.DB(p.dbName).C(CollectionLastStatuses)
		c.Update(bsonSelector, bsonUpdate)
	}
}

func (p *DBOperation) setReceiverStatus(rid string, status int) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	c.Update(bson.M{"rid": rid}, bson.M{"$set": bson.M{"status": status}})

	c = s.DB(p.dbName).C(CollectionLastStatuses)
	c.Update(bson.M{"rid": rid}, bson.M{"$set": bson.M{"status": status}})
}

type RawDataT struct {
	ID     bson.ObjectId `bson:"_id" json:"id"`
	Rid    string        `bson:"imei" json:"rid"`
	Type   string        `bson:"dt" json:"type"`
	Time   int           `bson:"t" json:"time"`
	Data   string        `bson:"data" json:"data"`
	Status int           `bson:"stat" json:"stat"`
	Err    string        `bson:"err" json:"error"`
}

func (p *DBOperation) rawDataCollectionName(date int) string {
	ts := ""

	if date == 0 {
		ts = time.Now().Format("0601")
	} else {
		date /= 100
		ts = strconv.Itoa(date)
	}
	if ts < "2112" {
		ts = ""
	}

	return ts
}

func (p *DBOperation) receiverRawData(rid, dataType string, date int, page int) (int, []RawDataT) {
	s := p.session.Copy()
	defer s.Close()
	c := s.DB(p.dbName).C(CollectionRawDatas + p.rawDataCollectionName(date))

	const PageCount int = 10

	var res []RawDataT
	bsonQuery := bson.M{}
	if rid != "" {
		bsonQuery["imei"] = rid
	}
	if dataType != "" {
		bsonQuery["dt"] = dataType
	}
	if date != 0 {
		d1 := IntToTime(date)
		d2 := d1.AddDate(0, 0, 1)
		oid1 := p.timeToObjectId(d1)
		oid2 := p.timeToObjectId(d2)
		bsonQuery["_id"] = bson.M{"$gte": oid1, "$lt": oid2}
		// bsonOid1 := bson.M{"_id": bson.M{"$gte": oid1}}
		// bsonOid2 := bson.M{"_id": bson.M{"$lt": oid2}}
		// bsonOids := []bson.M{bsonOid1, bsonOid2}
		// bsonQuery["$and"] = bsonOids
	}

	total, err := c.Find(bsonQuery).Count()
	if err != nil || total == 0 {
		return 0, nil
	}

	c.Find(bsonQuery).Select(bson.M{"_id": 1, "imei": 1, "dt": 1, "t": 1, "data": 1, "stat": 1, "err": 1}).Skip(page * PageCount).
		Limit(PageCount).Sort("-_id").All(&res)
	return total, res
}

func (p *DBOperation) timeToObjectId(t time.Time) bson.ObjectId {
	// year := date / 10000
	// month := (date % 10000) / 100
	// day := date % 100
	// if year < 2000 {
	// 	year += 2000
	// }
	// sDate := fmt.Sprintf("%d-%02d-%02d", year, month, day)
	// t, _ := time.Parse("2006-01-02", sDate)
	// t := IntToTime(date)
	// fmt.Println(t.Unix())
	sId := fmt.Sprintf("%x0000000000000000", t.Unix())
	return bson.ObjectIdHex(sId)
}

func (p *DBOperation) receiverImport(rt int, rids []string) (failedCount int, faileds []string) {
	s := p.session.Copy()
	defer s.Close()
	c := s.DB(p.dbName).C(CollectionReceivers)

	faileds = make([]string, 0)
	var err error

	for _, rid := range rids {
		rid = strings.Trim(rid, " ")
		err = c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 1}).One(nil)
		if err == nil {
			failedCount++
			faileds = append(faileds, rid)
		} else {
			err = c.Insert(bson.M{"rid": rid, "type": rt, "status": 0})
			if err != nil {
				failedCount++
				faileds = append(faileds, rid)
			}
		}
	}
	return
}

func (p *DBOperation) receiverChangeType(rt int, rids []string) {
	s := p.session.Copy()
	defer s.Close()

	// db.receivers.update({"rid":{"$in":["030319110257","030319110215"]}}, {"$set":{"type":5}},false,true)
	// db.laststatuses.update({"rid":{"$in":["030319110257","030319110215"]}}, {"$set":{"type":5}},false,true)
	bsonQuery := bson.M{"rid": bson.M{"$in": rids}}
	bsonUpdate := bson.M{"$set": bson.M{"type": rt}}

	c := s.DB(p.dbName).C(CollectionReceivers)
	c.UpdateAll(bsonQuery, bsonUpdate)

	c = s.DB(p.dbName).C(CollectionLastStatuses)
	c.UpdateAll(bsonQuery, bsonUpdate)

	c = s.DB(p.dbName).C(CollectionVehicles)
	c.UpdateAll(bsonQuery, bsonUpdate)
}

func (p *DBOperation) receiverSetToCompany(cid int, tid string, rids []string) {
	s := p.session.Copy()
	defer s.Close()
	c := s.DB(p.dbName).C(CollectionOrganizationProperties)
	cReceivers := s.DB(p.dbName).C(CollectionReceivers)

	var bsonData bson.M
	for _, rid := range rids {
		rid = strings.Trim(rid, " ")
		if rid != "" {
			if tid != "" {
				tids := p.getTeamParents(tid)
				for _, v := range tids {
					bsonData = bson.M{"tid": v, "rid": rid}
					c.Upsert(bsonData, bsonData)

					if cReceivers.Find(bson.M{"rid": rid, "tids": v}).Select(bson.M{"_id": 1}).One(nil) != nil {
						cReceivers.Update(bson.M{"rid": rid}, bson.M{"$push": bson.M{"tids": v}})
					}
				}
			}
			if cid != 0 {
				bsonData = bson.M{"cid": cid, "rid": rid}
				c.Upsert(bsonData, bsonData)

				if cReceivers.Find(bson.M{"rid": rid, "cid": cid}).Select(bson.M{"_id": 1}).One(nil) != nil {
					cReceivers.Update(bson.M{"rid": rid}, bson.M{"$set": bson.M{"cid": cid}})
				}
			}
		}
	}
}

func (p *DBOperation) receiverRemoveFromCompany(cid int, tid string, rids []string) {
	s := p.session.Copy()
	defer s.Close()
	c := s.DB(p.dbName).C(CollectionOrganizationProperties)
	cReceiver := s.DB(p.dbName).C(CollectionReceivers)

	var bsonData bson.M
	for _, rid := range rids {
		rid = strings.Trim(rid, " ")
		if rid != "" {
			if tid != "" {
				tids := p.getTeamChilden(tid)
				for _, v := range tids {
					bsonData = bson.M{"tid": v, "rid": rid}
					c.Remove(bsonData)

					cReceiver.Update(bson.M{"rid": rid}, bson.M{"$pull": bson.M{"tids": v}})
				}
			}
			if cid != 0 {
				bsonData = bson.M{"cid": cid, "rid": rid}
				c.Remove(bsonData)

				cReceiver.Update(bson.M{"rid": rid}, bson.M{"$set": bson.M{"cid": 0}})
			}
		}
	}
}

type ReceiverBelongT struct {
	Cid  int      `bson:"cid"`
	Tids []string `bson:"tids"`
}

func (p *DBOperation) receiverBelong(rid string) string {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	var rbs ReceiverBelongT

	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "cid": 1, "tids": 1}).One(&rbs)
	if err != nil {
		return ""
	}

	var result, name string
	if rbs.Cid != 0 {
		name = p.getCompanyName(rbs.Cid)
	}
	if name != "" {
		result += name + ";"
	}
	for i := 0; i < len(rbs.Tids); i++ {
		name = ""
		if rbs.Tids[i] != "" {
			name = p.getTeamName(rbs.Tids[i])
		}
		if name != "" {
			result += name + ";"
		}
	}

	return result
}

func (p *DBOperation) receiverClean(rids []string) {
	s := p.session.Copy()
	defer s.Close()
	// db.receivers.remove({"rid":{"$in":["030319100019","030319110366"]}})
	// db.receivers.save({ "rid" : "030319100019", "type" : 3, "status" : 0 })
	// db.receivers.save({ "rid" : "030319110366", "type" : 3, "status" : 0 })
	bsonQuery := bson.M{"rid": bson.M{"$in": rids}}
	c := s.DB(p.dbName).C(CollectionReceivers)
	c.UpdateAll(bsonQuery, bson.M{"$unset": bson.M{"iccid": 1, "vid": 1, "ct": 1, "at": 1, "cnum": 1, "serverid": 1, "serverport": 1,
		"newserverip": 1, "newserverport": 1, "gpsinterval": 1, "preinterval": 1, "registered": 1, "ma": 1,
		"dur": 1, "lt": 1, "hver": 1, "pcode": 1, "fver": 1, "threshold": 1, "cid": 1, "tids": 1, "plate": 1},
		"$set": bson.M{"status": 0}})
	c = s.DB(p.dbName).C(CollectionLastStatuses)
	c.UpdateAll(bsonQuery, bson.M{"$unset": bson.M{"plateno": 1, "convoy": 1, "ll": 1, "lp": 1, "lw": 1, "lm": 1, "lws": 1,
		"vol": 1}, "$set": bson.M{"status": 0}})

	c = s.DB(p.dbName).C(CollectionRelations)
	c.RemoveAll(bsonQuery)
	c = s.DB(p.dbName).C(CollectionOrganizationProperties)
	c.RemoveAll(bsonQuery)
	c = s.DB(p.dbName).C(CollectionTireWarnings)
	c.RemoveAll(bsonQuery)
	c = s.DB(p.dbName).C(CollectionTireWarningStatistics)
	c.RemoveAll(bsonQuery)
	c = s.DB(p.dbName).C(CollectionMileageStatistics)
	c.RemoveAll(bsonQuery)
	c = s.DB(p.dbName).C(CollectionTrackDates)
	c.RemoveAll(bsonQuery)
	c = s.DB(p.dbName).C(CollectionCommands)
	c.RemoveAll(bsonQuery)
	c = s.DB(p.dbName).C(CollectionTireDatas)
	c.RemoveAll(bsonQuery)
	c = s.DB(p.dbName).C(CollectionPositions)
	c.RemoveAll(bsonQuery)
}

func (p *DBOperation) receiverSetServer(ip string, port int, all int, rids []string) error {
	s := p.session.Copy()
	defer s.Close()
	c := s.DB(p.dbName).C(CollectionReceivers)

	bsonQuery := bson.M{}
	if all == 0 && rids != nil && len(rids) > 0 {
		bsonQuery["rid"] = bson.M{"$in": rids}
	}
	_, err := c.UpdateAll(bsonQuery, bson.M{"$set": bson.M{"newserverip": ip, "newserverport": port}})
	/*
		if err == nil {
			// 生成修改IP的指令 2022.10.17
			css := protocol808.CommandSetServer{}
			css.SerialNo = uint16(CreateSerialNo())
			css.ServerIP = ip
			css.ServerPort = port

			var msg, command string

			c = s.DB(p.dbName).C(CollectionCommands)
			for _, v := range rids {
				v = strings.TrimSpace(v)
				if v != "" {
					css.TerminalId = v
					msg, command = css.Pack()
					c.Insert(bson.M{"rid": v, "sn": css.SerialNo, "type": protocol808.PTSetParameter, "msg": msg, "command": command,
						"at": time.Now().Unix(), "stat": 0, "repeat": 0, "result": -1})
				}
			}
		}
	*/
	return err
}

func (p *DBOperation) receiverRemoteUpdate(fileUrl, productor, firmwareVer, softwareVer string, rids []string) {
	s := p.session.Copy()
	defer s.Close()
	c := s.DB(p.dbName).C(CollectionCommands)

	ru := protocol808.RemoteUpdate{}
	ru.SerialNo = uint16(CreateSerialNo())
	ru.FirmwareVersion = firmwareVer
	ru.Productor = productor
	ru.SoftwareVersion = softwareVer
	ru.Url = fileUrl

	var msg, command string
	for _, v := range rids {
		v = strings.TrimSpace(v)
		ru.TerminalId = v
		msg, command = ru.Pack()

		c.Insert(bson.M{"rid": v, "sn": ru.SerialNo, "type": protocol808.PTRemoteUpdate, "msg": msg, "command": command,
			"at": time.Now().Unix(), "stat": 0, "repeat": 0, "result": -1})
	}
}

func (p *DBOperation) receiverSetScreen(dsp *DeviceScreenParamT) error {
	s := p.session.Copy()
	defer s.Close()
	c := s.DB(p.dbName).C(CollectionCommands)

	ss := protocol808.CommandSetScreen{
		// SerialNo:        uint16(CreateSerialNo()),
		TerminalId:      dsp.Rid,
		Voice:           dsp.Voice,
		TemperatureUnit: dsp.TempUnit,
		PressureUnit:    dsp.PresUnit,
		VehicleType:     dsp.VehicleType,
	}
	ss.SerialNo = uint16(CreateSerialNo())

	msg, command := ss.Pack()
	return c.Insert(bson.M{"rid": dsp.Rid, "sn": ss.SerialNo, "type": protocol808.PTSetParameter, "msg": msg,
		"command": command, "at": time.Now().Unix(), "stat": 0, "repeat": 0, "result": -1})
}

type ReceiverDetailT struct {
	Rid           string `bson:"rid" json:"rid"`
	Type          int    `bson:"type" json:"type"`
	Iccid         string `bson:"iccid" json:"iccid"`
	IMEI          string `bson:"imei" json:"imei"`
	ServerIP      string `bson:"serverip" json:"serverip"`
	ServerPort    int    `bson:"serverport" json:"serverport"`
	NewServerIP   string `bson:"newserverip" json:"newserverip"`
	NewServerPort int    `bson:"newserverport" json:"newserverport"`
	GpsInterval   int    `bson:"gpsinterval" json:"gpsinterval"`
	PreInterval   int    `bson:"preinterval" json:"preinterval"`
	AuthCode      string `bson:"authcode" json:"authcode"`
	Lt            int64  `bson:"lt" json:"lt"`
	Hver          string `bson:"hver" json:"hver"`
	PCode         string `bson:"pcode" json:"pcode"`
	TVer          string `bson:"tver" json:"-"`
	// PCode         string `json:"pcode"`
	Fver      string `bson:"fver" json:"fver"`
	Status    int    `bson:"status" json:"status"`
	Threshold struct {
		Pressure     [5][2]float32 `bson:"pres" json:"pressure"`
		Tempetrature int           `bson:"temp" json:"tempetrature"`
	} `bson:"threshold" json:"threshold"`
}

func (p *DBOperation) receiverDetail(rid string) (ReceiverDetailT, error) {
	s := p.session.Copy()
	defer s.Close()
	c := s.DB(p.dbName).C(CollectionReceivers)

	var detail ReceiverDetailT
	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0}).One(&detail)
	if err == nil {
		detail.PCode = detail.PCode + "/" + detail.TVer
	}
	return detail, err
}

func (p *DBOperation) receiverThreshold(rid string) (*ReceiverThresholdDBT, error) {
	s := p.session.Copy()
	defer s.Close()
	c := s.DB(p.dbName).C(CollectionReceivers)

	var rt ReceiverThresholdDBT
	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "rid": 1, "type": 1, "threshold": 1}).One(&rt)
	return &rt, err
}

func (p *DBOperation) receiverFrequncy(rid string) (int, int) {
	s := p.session.Copy()
	defer s.Close()
	c := s.DB(p.dbName).C(CollectionReceivers)

	var res struct {
		GpsInterval int `bson:"gpsinterval"`
		PreInterval int `bson:"preinterval"`
	}
	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "gpsinterval": 1, "preinterval": 1}).One(&res)
	if err != nil {
		return 0, 0
	}

	return res.GpsInterval, res.PreInterval
}

func (p *DBOperation) receiverLocation(rid, mapType string) (lat, lng float64, err error) {
	type ReceiverLastLocationT struct {
		Lat  float64 `bson:"lat"`
		Lng  float64 `bson:"lng"`
		LatB float64 `bson:"latb"`
		LngB float64 `bson:"lngb"`
		LatG float64 `bson:"latg"`
		LngG float64 `bson:"lngg"`
	}
	type ReceiverLLT struct {
		LastLocation ReceiverLastLocationT `bson:"ll"`
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionLastStatuses)
	var rll ReceiverLLT
	err = c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "ll": 1}).One(&rll)
	if err != nil {
		return
	}
	if mapType == GpsGCJ02 {
		lat = rll.LastLocation.LatG
		lng = rll.LastLocation.LngG
	} else if mapType == GpsBd09 {
		lat = rll.LastLocation.LatB
		lng = rll.LastLocation.LngB
	} else {
		lat = rll.LastLocation.Lat
		lng = rll.LastLocation.Lng
	}

	return
}

func (p *DBOperation) receiverTrackDates(rid string, year, month int) string {
	s := p.session.Copy()
	defer s.Close()

	var res map[string][]int

	c := s.DB(p.dbName).C(CollectionTrackDates)
	err := c.Find(bson.M{"rid": rid, "year": year, "month": month}).Select(bson.M{"days": 1}).One(&res)
	if err != nil {
		return ""
	}

	days := res["days"]
	if days == nil {
		return ""
	}
	sRes := ""
	for _, v := range days {
		sRes += strconv.Itoa(v) + ","
	}

	iLen := len(sRes)
	if iLen > 0 && sRes[iLen-1] == ',' {
		sRes = sRes[:iLen-1]
	}

	return sRes
}

func (p *DBOperation) receiverSetFixTempAndPres(userId, rid string, temp int, press float64) error {
	if !p.userHaveReceiver(userId, rid) {
		return errors.New("您没有该设备")
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	return c.Update(bson.M{"rid": rid}, bson.M{"$set": bson.M{"fixtemp": temp, "fixpress": press}})
}

func (p *DBOperation) receiverFixTempAndPres(userId, rid string) (int, float64, error) {
	if !p.userHaveReceiver(userId, rid) {
		return 0, 0, errors.New("您没有该设备")
	}

	type FixTempAndPres struct {
		Temp  int     `bson:"fixtemp"`
		Press float64 `bson:"fixpress"`
	}
	var ftp FixTempAndPres

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	err := c.Find(bson.M{"rid": rid}).Select(bson.M{"_id": 0, "fixtemp": 1, "fixpress": 1}).One(&ftp)
	if err != nil {
		return 0, 0.0, err
	}

	return ftp.Temp, ftp.Press, nil
}

func (p *DBOperation) tireWarningHandle(id string, misalert int, result string) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireWarnings)
	if bson.IsObjectIdHex(id) {
		oid := bson.ObjectIdHex(id)
		if misalert == 1 {
			c.Update(bson.M{"_id": oid}, bson.M{"$set": bson.M{"stat": 4}})
		} else {
			c.Update(bson.M{"_id": oid}, bson.M{"$set": bson.M{"stat": 2, "result": result}})
		}

		var res map[string]string

		err := c.Find(bson.M{"_id": oid}).Select(bson.M{"_id": 0, "rid": 1}).One(&res)
		if err == nil {
			rid := res["rid"]
			if rid != "" {
				c = s.DB(p.dbName).C(CollectionWarningDeals)
				c.Insert(bson.M{"wid": id, "rid": rid, "stat": 0})
			}
		}
	}
}

func (p *DBOperation) tirewarningNew(cids []int, tids []string, t int) int {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	bsonMatch := bson.M{}
	if len(cids) > 0 {
		bsonMatch["cid"] = bson.M{"$in": cids}
	}
	if len(tids) > 0 {
		bsonMatch["tids"] = bson.M{"$in": tids}
	}
	pipeline := []bson.M{
		{"$match": bsonMatch},
		{"$lookup": bson.M{"from": "laststatuses", "localField": "rid", "foreignField": "rid", "as": "laststatuses"}},
		{"$match": bson.M{"laststatuses.lw.t": bson.M{"$gt": t}}},
		{"$count": "alertCount"},
	}

	var res map[string]int
	err := c.Pipe(pipeline).One(&res)
	if err != nil {
		return 0
	}
	return res["alertCount"]
}

func (p *DBOperation) tirewarningSetConcernedTeams(userid string, cids []int, tids []string) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCustomers)
	oid := bson.ObjectIdHex(userid)

	c.Update(bson.M{"_id": oid}, bson.M{"$set": bson.M{"alert.cids": cids, "alert.tids": tids}})
}

type ConcernedTeamDB struct {
	Alert struct {
		Cids []int    `json:"cids"`
		Tids []string `json:"tids"`
	} `json:"alert"`
}

type ConcernedCompanyT struct {
	Cid  int    `json:"cid"`
	Name string `json:"name"`
}

type ConcernedTeamT struct {
	Tid  string `json:"tid"`
	Name string `json:"name"`
}

type ConcernedTeam struct {
	Companies []ConcernedCompanyT `json:"companies"`
	Teams     []ConcernedTeamT    `json:"teams"`
}

func (p *DBOperation) tirewarningConcernedTeams(userid string) (*ConcernedTeam, error) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCustomers)
	oid := bson.ObjectIdHex(userid)
	var ct ConcernedTeamDB

	err := c.Find(bson.M{"_id": oid}).Select(bson.M{"_id": 0, "alert": 1}).One(&ct)
	if err != nil {
		return nil, err
	}

	res := ConcernedTeam{}
	res.Companies = make([]ConcernedCompanyT, 0)
	res.Teams = make([]ConcernedTeamT, 0)

	for _, v := range ct.Alert.Cids {
		if v != 0 {
			c := ConcernedCompanyT{Cid: v}
			c.Name = p.getCompanyName(v)
			res.Companies = append(res.Companies, c)
		}
	}

	for _, v := range ct.Alert.Tids {
		if v != "" {
			t := ConcernedTeamT{Tid: v}
			t.Name = p.getTeamName(v)
			res.Teams = append(res.Teams, t)
		}
	}

	return &res, nil
}

func (p *DBOperation) tirewarningSetConcernedTypes(userid string, types []int) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCustomers)
	oid := bson.ObjectIdHex(userid)

	c.Update(bson.M{"_id": oid}, bson.M{"$set": bson.M{"alert.types": types}})
}

func (p *DBOperation) tirewarningConcernedTypes(userid string) []int {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCustomers)
	oid := bson.ObjectIdHex(userid)

	var res map[string]map[string][]int
	err := c.Find(bson.M{"_id": oid}).Select(bson.M{"alert.types": 1, "_id": 0}).One(&res)

	if err != nil {
		return nil
	}

	return res["alert"]["types"]
}

type AlertMailT struct {
	Send bool   `bson:"send" json:"send"`
	SMTP string `bson:"smtp" json:"smtp"`
	Port string `bson:"port" json:"port"`
	User string `bson:"user" json:"user"`
	Pass string `bson:"pass" json:"pass"`
	To   string `bson:"to" json:"to"`
}

func (p *DBOperation) tirewarningSetMail(userid string, am *AlertMailT) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCustomers)
	oid := bson.ObjectIdHex(userid)
	c.Update(bson.M{"_id": oid}, bson.M{"$set": bson.M{"alert.mail": am}})
}

func (p *DBOperation) tirewarningMail(userid string) *AlertMailT {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCustomers)
	oid := bson.ObjectIdHex(userid)
	var res map[string]map[string]AlertMailT
	var am AlertMailT
	err := c.Find(bson.M{"_id": oid}).Select(bson.M{"_id": 0, "alert.mail": 1}).One(&res)
	if err != nil {
		am = AlertMailT{}
	}
	am = res["alert"]["mail"]
	return &am
}

type CommandT struct {
	Rid     string `bson:"rid" json:"rid"`
	SN      int    `bson:"sn" json:"sn"`
	Type    string `bson:"type" json:"type"`
	Command string `bson:"command" json:"command"`
	At      int    `bson:"at" json:"at"`
	Stat    int    `bson:"stat" json:"stat"`
	St      int    `bson:"st" json:"st"`
	Rt      int    `bson:"rt" json:"rt"`
	Result  int    `bson:"result" json:"result"`
}

func (p *DBOperation) commandList(rid string, msgType string, stat int, result int, page int) (total int, commands []CommandT) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionCommands)
	bsonQuery := bson.M{}

	if rid != "" {
		bsonQuery["rid"] = rid
	}
	if msgType != "" {
		bsonQuery["type"] = msgType
	}
	if stat != 9 {
		bsonQuery["stat"] = stat
	}
	if result != 9 {
		bsonQuery["result"] = result
	}

	total, _ = c.Find(bsonQuery).Count()
	if total == 0 {
		return 0, nil
	}

	c.Find(bsonQuery).Select(bson.M{"_id": 0, "msg": 0}).Skip(page * 10).Limit(10).All(&commands)

	return
}

type WorkTimeT struct {
	Name         string `json:"name"`
	WorkTime     int    `json:"worktime"`
	AbnormalTime int    `json:"abnormaltime"`
	NormalTime   int    `json:"normaltime"`
}

func (p *DBOperation) reportWorkTime(cids []string, tids []string, beginDate int, endDate int) ([]WorkTimeT, error) {
	s := p.session.Copy()
	defer s.Close()

	var iCid int
	var err error

	wts := make([]WorkTimeT, 0)
	var rids []string

	for _, v := range cids {
		if v != "" {
			iCid, err = strconv.Atoi(v)
			if err == nil && iCid > 0 {
				wt := WorkTimeT{}
				wt.Name = p.getCompanyName(iCid)
				rids = p.companyReceivers(iCid, "")
				wt.WorkTime, wt.AbnormalTime = p.receiversWorkTime(rids, beginDate, endDate)
				wt.NormalTime = wt.WorkTime - wt.AbnormalTime

				wts = append(wts, wt)
			}
		}
	}
	for _, v := range tids {
		if v != "" {
			wt := WorkTimeT{}
			wt.Name = p.getTeamName(v)
			rids = p.teamReceivers(v, "")
			wt.WorkTime, wt.AbnormalTime = p.receiversWorkTime(rids, beginDate, endDate)
			wt.NormalTime = wt.WorkTime - wt.AbnormalTime

			wts = append(wts, wt)
		}
	}

	return wts, nil
}

type WorkTimeSumT struct {
	TotalWt  int `json:"totalwt"`
	TotalAwt int `json:"totalawt"`
}

func (p *DBOperation) receiversWorkTime(rids []string, beginDate, endDate int) (workTime int, abnormalTime int) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTimeStatistics)

	// bsonDate := make([]bson.M, 0)
	// bsonDate = append(bsonDate, bson.M{"date": bson.M{"$gte": beginDate}})
	// bsonDate = append(bsonDate, bson.M{"date": bson.M{"$lte": endDate}})
	// "$and": bsonDate}}, //
	pipeline := []bson.M{
		{"$match": bson.M{"rid": bson.M{"$in": rids}, "date": bson.M{"$gte": beginDate, "$lte": endDate}}},
		{"$group": bson.M{"_id": 1, "totalwt": bson.M{"$sum": "$wt"}, "totalawt": bson.M{"$sum": "$awt"}}},
		//, "totalawt": bson.M{"$sum": "$awt"}
	}

	var res WorkTimeSumT
	err := c.Pipe(pipeline).One(&res)
	if err == nil {
		return res.TotalWt, res.TotalAwt
	}
	// else {
	// 	fmt.Println(err)
	// 	fmt.Println(pipeline)
	// }

	return 0, 0
}

func (p *DBOperation) companyDeviceCount(cid int) int {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionOrganizationProperties)
	filter := bson.M{}
	if cid != 0 {
		filter["cid"] = cid
	}
	filter["rid"] = bson.M{"$exists": 1}
	//count, _ := c.Find(bson.M{"cid": cid, "rid": bson.M{"$exists": 1}}).Count()
	count, _ := c.Find(filter).Count()
	return count
}

func (p *DBOperation) companyReceiverCount(cid int) int {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	filter := bson.M{}
	if cid != 0 {
		filter["cid"] = cid
	}
	count, _ := c.Find(filter).Count()
	return count
}

func (p *DBOperation) companyVehicleCount(cid int) int {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionOrganizationProperties)
	filter := bson.M{}
	if cid != 0 {
		filter["cid"] = cid
	}
	filter["vid"] = bson.M{"$exists": 1}
	count, _ := c.Find(filter).Count()
	//count, _ := c.Find(bson.M{"cid": cid, "vid": bson.M{"$exists": 1}}).Count()
	return count
}

func (p *DBOperation) companyVehicleCount2(cid int) int {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicles)
	filter := bson.M{}
	if cid != 0 {
		filter["cid"] = cid
	}
	count, _ := c.Find(filter).Count()
	return count
}

func (p *DBOperation) companyAlertCount(cid int, date int) int {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireWarnings)

	if date > 20000000 {
		date = date - 20000000
	}
	filter := bson.M{}
	if cid != 0 {
		rids := p.companyReceivers(cid, "")
		filter["rid"] = bson.M{"$in": rids}
	}
	filter["date"] = date
	count, _ := c.Find(filter).Count()
	//count, _ := c.Find(bson.M{"rid": bson.M{"$in": rids}, "date": date}).Count()
	return count
}

func (p *DBOperation) receiversAlertCount(rids []string, date int) int {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireWarnings)

	if date > 20000000 {
		date = date - 20000000
	}
	filter := bson.M{}

	if len(rids) > 0 {
		filter["rid"] = bson.M{"$in": rids}
	}
	filter["date"] = date
	// filter := bson.M{"rid": , "date": date}
	count, _ := c.Find(filter).Count()
	return count
}

func (p *DBOperation) companyMileage(cid int, d int) int {
	type MileageT struct {
		Mileage float32 `bson:"mileage"`
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionMileageStatistics)
	var ma MileageT

	if d > 20000000 {
		d = d - 20000000
	}
	bsonMatch := bson.M{} //"rid": bson.M{"$in": rids}, "date": d}
	if cid != 0 {
		rids := p.companyReceivers(cid, "")
		if len(rids) == 0 {
			return 0
		}
		bsonMatch["rid"] = bson.M{"$in": rids}
	}
	bsonMatch["date"] = d
	bsonGroup := bson.M{"_id": bson.M{}, "mileage": bson.M{"$sum": "$ma"}}
	pipeline := []bson.M{
		{"$match": bsonMatch},
		{"$group": bsonGroup},
	}
	err := c.Pipe(pipeline).One(&ma)
	if err == nil {
		return int(ma.Mileage)
	}
	// }

	return 0
}

func (p *DBOperation) receiversMileage(rids []string, d int) int {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionMileageStatistics)
	var ma struct {
		Mileage float32 `bson:"mileage"`
	}

	if d > 20000000 {
		d = d - 20000000
	}

	bsonMatch := bson.M{}
	if len(rids) > 0 {
		bsonMatch["rid"] = bson.M{"$in": rids}
	}
	bsonMatch["date"] = d
	// bsonMatch := bson.M{"rid":, "date": d}
	bsonGroup := bson.M{"_id": bson.M{}, "mileage": bson.M{"$sum": "$ma"}}
	pipeline := []bson.M{
		{"$match": bsonMatch},
		{"$group": bsonGroup},
	}
	err := c.Pipe(pipeline).One(&ma)
	if err == nil {
		return int(ma.Mileage)
	}

	return 0
}

func (p *DBOperation) teamCost(cid int, tid string, d int) float64 {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionWorkOrders)
	filter := bson.M{}

	if cid != 0 {
		filter["cid"] = cid
	}
	if tid != "" {
		filter["tids"] = tid
	}
	if d != 0 {
		filter["date"] = d
	}

	var sumRes struct {
		Cost float64 `bson:"cost"`
	}

	matchStage := bson.M{"$match": filter}
	groupStage := bson.M{"$group": bson.M{"_id": nil, "cost": bson.M{"$sum": "$cost"}}}
	err := c.Pipe([]bson.M{matchStage, groupStage}).One(&sumRes)
	if err != nil {
		return 0
	}

	return sumRes.Cost
}

type AlertCountT struct {
	ID    int `bson:"_id"`
	Count int `bson:"count"`
}

func (p *DBOperation) companyAlertDetail(cid int, d int) []AlertCountT {
	s := p.session.Copy()
	defer s.Close()

	var res []AlertCountT
	c := s.DB(p.dbName).C(CollectionTireWarnings)
	bsonMatch := bson.M{} //"rid": bson.M{"$in": rids}, "date": d}
	if cid != 0 {
		rids := p.companyReceivers(cid, "")
		if len(rids) > 0 {
			return nil
		}
		bsonMatch["rid"] = bson.M{"$in": rids}
	}
	bsonMatch["date"] = d
	bsonGroup := bson.M{"_id": "$wt", "count": bson.M{"$sum": 1}}
	pipeline := []bson.M{
		{"$match": bsonMatch},
		{"$group": bsonGroup},
	}
	c.Pipe(pipeline).All(&res)
	return res
}

func (p *DBOperation) receiversAlertDetail(rids []string, d int) []AlertCountT {
	s := p.session.Copy()
	defer s.Close()

	var res []AlertCountT
	c := s.DB(p.dbName).C(CollectionTireWarnings)
	bsonMatch := bson.M{}
	if len(rids) > 0 {
		bsonMatch["rid"] = bson.M{"$in": rids}
	}
	bsonMatch["date"] = d
	bsonGroup := bson.M{"_id": "$wt", "count": bson.M{"$sum": 1}}
	pipeline := []bson.M{
		{"$match": bsonMatch},
		{"$group": bsonGroup},
	}
	c.Pipe(pipeline).All(&res)
	return res
}

func (p *DBOperation) companyOnlineStatus(cid int) (int, int) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionLastStatuses)
	bsonQuery := []bson.M{{"status": 1}, {"status": -1}}
	var total, onlineCount int
	t := time.Now().Unix() - ReceiverOfflineInterval

	if cid != 0 {
		rids := p.companyReceivers(cid, "")
		if len(rids) == 0 {
			return 0, 0
		}
		total, _ = c.Find(bson.M{"rid": bson.M{"$in": rids}, "$or": bsonQuery}).Count()
		onlineCount, _ = c.Find(bson.M{"rid": bson.M{"$in": rids}, "$or": bsonQuery, "lt": bson.M{"$gt": t}}).Count()
	} else {
		total, _ = c.Find(bson.M{"$or": bsonQuery}).Count()
		onlineCount, _ = c.Find(bson.M{"$or": bsonQuery, "lt": bson.M{"$gt": t}}).Count()
	}

	return onlineCount, total - onlineCount
}

func (p *DBOperation) receiversOnlineStatus(rids []string) (int, int) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionLastStatuses)
	bsonQuery := []bson.M{{"status": 1}, {"status": -1}}
	filter := bson.M{}
	if len(rids) > 0 {
		filter["rid"] = bson.M{"$in": rids}
	}
	filter["$or"] = bsonQuery

	var total, onlineCount int
	t := time.Now().Unix() - ReceiverOfflineInterval

	total, _ = c.Find(filter).Count()
	filter["lt"] = bson.M{"$gt": t}
	onlineCount, _ = c.Find(filter).Count()

	return onlineCount, total - onlineCount
}

func (p *DBOperation) companySensorOnline(cid, t int) (int, int) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	bsonMatch := bson.M{}
	if cid != 0 {
		bsonMatch["cid"] = cid
	}
	bsonMatch["$or"] = []bson.M{{"status": 1}, {"status": -1}}
	matchStage := bson.M{"$match": bsonMatch}
	lookupStage := bson.M{"$lookup": bson.M{"from": "laststatuses", "localField": "rid", "foreignField": "rid", "as": "last"}}
	projectStage := bson.M{"$project": bson.M{"last.lp": 1, "_id": 0}}
	unwindLpStage := bson.M{"$unwind": "$last"}
	unwindLptStage := bson.M{"$unwind": "$last.lp"}
	matchStage2 := bson.M{"$match": bson.M{"last.lp.t": bson.M{"$gt": t}}}
	countStage := bson.M{"$count": "count"}

	bsonPipelineTotle := []bson.M{
		matchStage,
		lookupStage,
		projectStage,
		unwindLpStage,
		unwindLptStage,
		countStage,
	}

	bsonPipelineOnline := []bson.M{
		matchStage,
		lookupStage,
		projectStage,
		unwindLpStage,
		unwindLptStage,
		matchStage2,
		countStage,
	}

	var res struct {
		Count int `bson:"count"`
	}
	var total, online int

	err := c.Pipe(bsonPipelineTotle).One(&res)
	if err == nil {
		total = res.Count
		err = c.Pipe(bsonPipelineOnline).One(&res)
		if err == nil {
			online = res.Count
		}
	}
	return online, total - online
}

func (p *DBOperation) teamSensorOnline(tid string, t int) (int, int) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	bsonMatch := bson.M{}
	if tid != "" {
		bsonMatch["tids"] = tid
	} else {
		return 0, 0
	}
	bsonMatch["$or"] = []bson.M{{"status": 1}, {"status": -1}}
	matchStage := bson.M{"$match": bsonMatch}
	lookupStage := bson.M{"$lookup": bson.M{"from": "laststatuses", "localField": "rid", "foreignField": "rid", "as": "last"}}
	projectStage := bson.M{"$project": bson.M{"last.lp": 1, "_id": 0}}
	unwindLpStage := bson.M{"$unwind": "$last"}
	unwindLptStage := bson.M{"$unwind": "$last.lp"}
	matchStage2 := bson.M{"$match": bson.M{"last.lp.t": bson.M{"$gt": t}}}
	countStage := bson.M{"$count": "count"}

	bsonPipelineTotle := []bson.M{
		matchStage,
		lookupStage,
		projectStage,
		unwindLpStage,
		unwindLptStage,
		countStage,
	}

	bsonPipelineOnline := []bson.M{
		matchStage,
		lookupStage,
		projectStage,
		unwindLpStage,
		unwindLptStage,
		matchStage2,
		countStage,
	}

	var res struct {
		Count int `bson:"count"`
	}
	var total, online int

	err := c.Pipe(bsonPipelineTotle).One(&res)
	if err == nil {
		total = res.Count
		err = c.Pipe(bsonPipelineOnline).One(&res)
		if err == nil {
			online = res.Count
		}
	}

	return online, total - online
}

func (p *DBOperation) companyNormalStatus(cid int) (int, int) {
	type NormalStatusT struct {
		Id   int `bson:"_id"`
		Warn int `bson:"warn"`
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionLastStatuses)
	bsonMatch := bson.M{}
	if cid != 0 {
		rids := p.companyReceivers(cid, "")
		if len(rids) == 0 {
			return 0, 0
		}
		bsonMatch["rid"] = bson.M{"$in": rids}
	}
	bsonMatch["lws"] = bson.M{"$exists": 1}
	bsonGroup := bson.M{"_id": "$lws.warn", "warn": bson.M{"$sum": 1}}
	bsonPipeline := []bson.M{
		{"$match": bsonMatch},
		{"$group": bsonGroup},
	}
	var res []NormalStatusT
	err := c.Pipe(bsonPipeline).All(&res)
	if err != nil {
		return 0, 0
	}

	var normal, abnormal int

	for _, v := range res {
		if v.Id == 0 {
			normal = v.Warn
		} else {
			abnormal = v.Warn
		}
	}
	return normal, abnormal
}

func (p *DBOperation) receiversNormalStatus(rids []string) (int, int) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionLastStatuses)
	bsonMatch := bson.M{}
	if len(rids) > 0 {
		bsonMatch["rid"] = bson.M{"$in": rids}
	}
	//bsonMatch["lws"] = bson.M{"$exists": 1}
	bsonGroup := bson.M{"_id": "$lws.warn", "warn": bson.M{"$sum": 1}}
	bsonPipeline := []bson.M{
		{"$match": bsonMatch},
		{"$group": bsonGroup},
	}
	var res []struct {
		Id   int `bson:"_id"`
		Warn int `bson:"warn"`
	}
	err := c.Pipe(bsonPipeline).All(&res)
	if err != nil {
		return 0, 0
	}

	var normal, abnormal int

	for _, v := range res {
		if v.Id == 0 {
			normal += v.Warn
		} else {
			abnormal += v.Warn
		}
	}
	return normal, abnormal
}

func (p *DBOperation) teamDeviceCount(tid string) int {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	count, _ := c.Find(bson.M{"tids": tid}).Count()
	return count
}

func (p *DBOperation) teamVehicleCount(tid string) int {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicles)       //(CollectionOrganizationProperties)
	count, _ := c.Find(bson.M{"tids": tid}).Count() //, "vid": bson.M{"$exists": 1}
	return count
}

func (p *DBOperation) teamAlertCount(tid string, date int) int {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireWarnings)
	rids := p.teamReceivers(tid, "")

	if date > 20000000 {
		date = date - 20000000
	}

	count, _ := c.Find(bson.M{"rid": bson.M{"$in": rids}, "date": date}).Count()
	return count
}

func (p *DBOperation) teamMileage(tid string, d int) int {
	type MileageT struct {
		Mileage float32 `bson:"mileage"`
	}

	rids := p.teamReceivers(tid, "")
	if len(rids) > 0 {
		s := p.session.Copy()
		defer s.Close()

		c := s.DB(p.dbName).C(CollectionMileageStatistics)
		var ma MileageT

		if d > 20000000 {
			d = d - 20000000
		}
		bsonMatch := bson.M{"rid": bson.M{"$in": rids}, "date": d}
		bsonGroup := bson.M{"_id": bson.M{}, "mileage": bson.M{"$sum": "$ma"}}
		pipeline := []bson.M{
			{"$match": bsonMatch},
			{"$group": bsonGroup},
		}
		err := c.Pipe(pipeline).One(&ma)
		if err == nil {
			return int(ma.Mileage)
		}
	}

	return 0
}

func (p *DBOperation) teamOnlineStatus(tid string) (int, int) {
	rids := p.teamReceivers(tid, "")
	if len(rids) > 0 {
		s := p.session.Copy()
		defer s.Close()

		c := s.DB(p.dbName).C(CollectionLastStatuses)
		bsonQuery := []bson.M{{"status": 1}, {"status": -1}}
		total, _ := c.Find(bson.M{"rid": bson.M{"$in": rids}, "$or": bsonQuery}).Count()

		t := time.Now().Unix() - ReceiverOfflineInterval
		onlineCount, _ := c.Find(bson.M{"rid": bson.M{"$in": rids}, "$or": bsonQuery, "lt": bson.M{"$gt": t}}).Count()

		return onlineCount, total - onlineCount
	}

	return 0, 0
}

func (p *DBOperation) teamNormalStatus(tid string) (int, int) {
	type NormalStatusT struct {
		Id   int `bson:"_id"`
		Warn int `bson:"warn"`
	}

	rids := p.teamReceivers(tid, "")
	if len(rids) > 0 {
		s := p.session.Copy()
		defer s.Close()

		c := s.DB(p.dbName).C(CollectionLastStatuses)
		bsonMatch := bson.M{"rid": bson.M{"$in": rids}, "lws": bson.M{"$exists": 1}}
		bsonGroup := bson.M{"_id": "$lws.warn", "warn": bson.M{"$sum": 1}}
		bsonPipeline := []bson.M{
			{"$match": bsonMatch},
			{"$group": bsonGroup},
		}
		var res []NormalStatusT
		err := c.Pipe(bsonPipeline).All(&res)
		if err != nil {
			return 0, 0
		}

		var normal, abnormal int

		for _, v := range res {
			if v.Id == 0 {
				normal = v.Warn
			} else {
				abnormal = v.Warn
			}
		}
		return normal, abnormal
	}

	return 0, 0
}

func (p *DBOperation) teamAlertDetail(tid string, d int) []AlertCountT {
	rids := p.teamReceivers(tid, "")
	if len(rids) > 0 {
		s := p.session.Copy()
		defer s.Close()

		var res []AlertCountT
		c := s.DB(p.dbName).C(CollectionTireWarnings)
		bsonMatch := bson.M{"rid": bson.M{"$in": rids}, "date": d}
		bsonGroup := bson.M{"_id": "$wt", "count": bson.M{"$sum": 1}}
		pipeline := []bson.M{
			{"$match": bsonMatch},
			{"$group": bsonGroup},
		}
		c.Pipe(pipeline).All(&res)
		return res
	}

	return nil
}

type DriverNameT struct {
	DriverId string `bson:"did" json:"driverid"`
	Name     string `bson:"name" json:"name"`
}

func (p *DBOperation) driverNameList(cid int, tid string) []DriverNameT {
	s := p.session.Copy()
	defer s.Close()

	var res []DriverNameT
	c := s.DB(p.dbName).C(CollectionDrivers)
	bsonQuery := bson.M{"cid": cid}
	if tid != "" {
		tids := p.getTeamChilden(tid)
		bsonQuery["tid"] = bson.M{"$in": tids} //tid
	}

	err := c.Find(bsonQuery).Select(bson.M{"_id": 0, "did": 1, "name": 1}).All(&res)
	if err != nil || res == nil {
		res = make([]DriverNameT, 0)
	}

	return res
}

type DriverT struct {
	DriverID   string `json:"driverid" bson:"did"`
	Name       string `json:"name" bson:"name"`
	IdCard     string `json:"idcard" bson:"idcard"`
	Cid        int    `json:"cid" bson:"cid"`
	Tid        string `json:"tid" bson:"tid"`
	Team       string `json:"team"`
	Gender     int    `json:"gender" bson:"gender"`
	Birthday   int    `json:"birthday"`
	DrivingAge int    `json:"drivingage" bson:"drivingage"`
	Phone      string `json:"phone" bson:"phone"`
	License    string `json:"license" bson:"license"`
	Photo      string `json:"photo" bson:"photo"`
}

func (p *DBOperation) driverList(cid int, tid, name string, page int) (int, []DriverT) {
	s := p.session.Copy()
	defer s.Close()

	var res []DriverT
	c := s.DB(p.dbName).C(CollectionDrivers)
	bsonQuery := bson.M{}
	if cid != 0 {
		bsonQuery["cid"] = cid
	}
	if tid != "" {
		tids := p.getTeamChilden(tid)
		bsonQuery["tid"] = bson.M{"$in": tids}
	}
	if name != "" {
		bsonReg := bson.RegEx{Pattern: name, Options: "im"}
		bsonQuery["name"] = bsonReg
	}

	count, err := c.Find(bsonQuery).Count()
	if err != nil {
		return 0, make([]DriverT, 0)
	}

	err = c.Find(bsonQuery).Select(bson.M{"_id": 0}).Skip(page * 10).Limit(10).All(&res)
	if err == nil {
		for i := 0; i < len(res); i++ {
			if res[i].Tid != "" {
				res[i].Team = p.getTeamName(res[i].Tid)
			} else {
				res[i].Team = p.getCompanyName(res[i].Cid)
			}
		}
	}
	if res == nil {
		res = make([]DriverT, 0)
	}

	return count, res
}

type DriverAddT struct {
	DriverID   string `json:"diverid" bson:"did"`
	Name       string `json:"name" bson:"name"`
	IdCard     string `json:"idcard" bson:"idcard"`
	Cid        int    `json:"cid" bson:"cid"`
	Tid        string `json:"tid" bson:"tid"`
	Gender     int    `json:"gender" bson:"gender"`
	Birthday   int    `json:"birthday"`
	DrivingAge int    `json:"drivingage" bson:"drivingage"`
	Phone      string `json:"phone" bson:"phone"`
	License    string `json:"license" bson:"license"`
	Photo      string `json:"photo" bson:"photo"`
}

func (p *DBOperation) driverAdd(da *DriverAddT) error {
	s := p.session.Copy()
	defer s.Close()

	var err error
	c := s.DB(p.dbName).C(CollectionDrivers)
	err = c.Find(bson.M{"idcard": da.IdCard}).One(nil)
	if err == nil {
		return errors.New("已经存在该司机信息")
	}

	err = c.Insert(da)

	return err
}

func (p *DBOperation) driverEdit(da *DriverAddT) error {
	s := p.session.Copy()
	defer s.Close()

	var err error
	c := s.DB(p.dbName).C(CollectionDrivers)
	err = c.Update(bson.M{"did": da.DriverID}, da)
	if err != nil {
		return err
	}

	return nil
}

func (p *DBOperation) driverDelete(driverid string) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionDrivers)
	c.Remove(bson.M{"did": driverid})
}

type SensorLastWarningT struct {
	Date     int     `json:"date" bson:"date"`
	Time     int     `json:"time" bson:"time"`
	Lat      float64 `json:"lat" bson:"lat"`
	Lng      float64 `json:"lng" bson:"lng"`
	LatB     float64 `json:"-" bson:"latb"`
	LngB     float64 `json:"-" bson:"lngb"`
	LatG     float64 `json:"-" bson:"latg"`
	LngG     float64 `json:"-" bson:"lngg"`
	Vol      float64 `json:"vol" bson:"vol"`
	Pres     float64 `json:"pres" bson:"pres"`
	Temp     int     `json:"temp" bson:"temp"`
	WarnType int     `json:"wt" bson:"wt"`
}

func (p *DBOperation) sensorLastWarning(sid, warnTypes, gpsType string) []*SensorLastWarningT {
	slws := []*SensorLastWarningT{}

	wts := strings.Split(warnTypes, ",")
	var iWarnType int
	var err error
	var slw *SensorLastWarningT
	for _, wt := range wts {
		iWarnType, err = strconv.Atoi(wt)
		if err == nil {
			slw = p.sensorSingleLastWarning(sid, iWarnType, gpsType)
			if slw != nil {
				slws = append(slws, slw)
			}
		}
	}

	return slws
}

func (p *DBOperation) sensorSingleLastWarning(sid string, warnType int, gpsType string) *SensorLastWarningT {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireWarnings)
	var slw SensorLastWarningT
	err := c.Find(bson.M{"sid": sid, "wt": warnType, "stat": 0}).
		Select(bson.M{"_id": 0, "date": 1, "time": 1, "lat": 1, "lng": 1, "latb": 1, "lngb": 1, "latg": 1, "lngg": 1,
			"vol": 1, "pres": 1, "temp": 1, "wt": 1}).
		Sort("-_id").
		Limit(1).
		One(&slw)

	if err != nil {
		return nil
	}
	if gpsType == GpsBd09 {
		slw.Lat = slw.LatB
		slw.Lng = slw.LngB
	} else if gpsType == GpsGCJ02 {
		slw.Lat = slw.LatG
		slw.Lng = slw.LngG
	}

	return &slw
}

func (p *DBOperation) maintainInstall(rid string, rType int, userid, operator, address, data string) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionEquipmentInstalls)
	d := today(0)
	if d < 20000000 {
		d += 20000000
	}
	c.Insert(bson.M{"rid": rid, "type": rType, "userid": userid, "operator": operator, "addr": address, "data": data, "stat": 0,
		"date": d, "t": time.Now().Unix()})
}

type EquipmentInstallT struct {
	Id       bson.ObjectId `bson:"_id" json:"id"`
	Rid      string        `bson:"rid" json:"rid"`
	Type     int           `bson:"type" json:"type"`
	Operator string        `bson:"operator" json:"operator"`
	Address  string        `bson:"addr" json:"address"`
	T        int64         `bson:"t" json:"t"`
	Stat     int           `bson:"stat" json:"stat"`
	Data     string        `bson:"data" json:"data"`
}

func (p *DBOperation) maintainInstallList(userid string, cid int, tid, rid string, d, stat, page int) (int, []EquipmentInstallT) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionEquipmentInstalls)
	bsonQuery := bson.M{}

	// if p.userType(userid) != UserTypeSystemUser {
	// 	rids := p.userReceiversEx(userid, cid, tid, rid)

	// 	if len(rids) == 0 {
	// 		return 0, nil
	// 	}

	// 	bsonQuery["rid"] = bson.M{"$in": rids}
	// }
	rids := p.getReceivers(userid, cid, tid, rid)
	if len(rids) == 0 {
		return 0, nil
	} else {
		bsonQuery["rid"] = bson.M{"$in": rids}

	}
	bsonQuery["stat"] = stat
	if d > 0 {
		bsonQuery["date"] = d
	}
	total, err := c.Find(bsonQuery).Count()
	if err != nil || total == 0 {
		return 0, make([]EquipmentInstallT, 0)
	}

	var res []EquipmentInstallT
	err = c.Find(bsonQuery).Select(bson.M{"data": 0}).Sort("-_id").Skip(page * 10).Limit(10).All(&res)
	if err != nil {
		return 0, make([]EquipmentInstallT, 0)
	}

	return total, res
}

func (p *DBOperation) maintainInstallInfo(id string) (*EquipmentInstallT, error) {
	if !bson.IsObjectIdHex(id) {
		return nil, errors.New("无效的ID号")
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionEquipmentInstalls)
	var ei EquipmentInstallT

	err := c.Find(bson.M{"_id": bson.ObjectIdHex(id)}).One(&ei)
	if err != nil {
		err = errors.New("未找到相应的装车信息")
		return nil, err
	}

	return &ei, nil
}

func (p *DBOperation) maintainCheck(mc *MaintainCheckT) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionVehicleChecks)
	err := c.Insert(mc)
	if err != nil {
		return err
	}

	cid, _ := p.getCompanyNameByRid(mc.Rid)
	tid, _ := p.getTeamNameByRid(mc.Rid)

	ta := TireActionT{Cid: cid, Tid: tid, Rid: mc.Rid, Operator: mc.Operator,
		Date: mc.Date, Time: mc.Time, T: time.Now().Unix(), Action: TireActionCheck}

	c = s.DB(p.dbName).C(CollectionTires)
	for _, v := range mc.Datas {
		if v.Tno != "" {
			c.Update(bson.M{"tno": v.Tno}, bson.M{"$set": bson.M{"cpdepths": v.Depth}})

			ta.Tno = v.Tno
			ta.Wid, _ = p.getWarehouseByTire(cid, v.Tno)
			ta.Cpdepths = v.Depth
			ta.Status, ta.Mileage = p.getTireStatus(cid, v.Tno)

			p.saveTireAction(&ta)
		}
	}

	return nil
}

func (p *DBOperation) SensorHasDatas(rid string, cardid, sn, d int) int {
	res := 0

	if rid != "" && d != 0 {
		s := p.session.Copy()
		defer s.Close()

		c := s.DB(p.dbName).C(CollectionTireDatas)
		filter := bson.M{"rid": rid, "cardid": cardid, "sn": sn, "date": d}
		if c.Find(filter).Select(bson.M{"_id": 1}).One(nil) == nil {
			res = 1
		}
	}

	return res
}

func (p *DBOperation) maintainFixtire(mft *MaintainFixTireT) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireFixes)
	err := c.Insert(mft)
	if err != nil {
		return err
	}

	var wo WorkOrderT
	wo.FromFixTire(mft)
	if wo.Tid != "" {
		wo.Team = p.getTeamName(wo.Tid)
	} else {
		wo.Team = p.getCompanyName(wo.Cid)
	}
	wo.Plate, _, _, _, _, _ = p.getPlateByRid(wo.Rid)
	woRec := wo.Records[0]
	wo.Records[0].HasData = p.SensorHasDatas(wo.Rid, woRec.Cardid, woRec.Sn, wo.Date)
	c = s.DB(p.dbName).C(CollectionWorkOrders)
	c.Insert(wo)

	ta := TireActionT{Cid: mft.Cid, Tid: mft.Tid, Rid: mft.Rid, Vid: mft.Vid, Tno: mft.Tno, Operator: mft.Operator,
		Date: mft.Date, Time: mft.Time, T: mft.T, Action: TireActionFix, Reason: mft.Remark}
	p.saveTireAction(&ta)

	return nil
}

func (p *DBOperation) maintainFixTireList(userid string, cid int, tid, tno string, date, page int) (int, []MaintainFixTireListT) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireFixes)
	bsonQuery := bson.M{}

	if cid == 0 {
		if p.userType(userid) != UserTypeSystemUser {
			return 0, make([]MaintainFixTireListT, 0)
		}
	} else {
		bsonQuery["cid"] = cid
	}

	if tid != "" {
		bsonQuery["tids"] = tid
	}

	if tno != "" {
		bsonQuery["tno"] = bson.RegEx{Pattern: tno, Options: "im"}
	}

	if date > 0 {
		bsonQuery["date"] = date
	}
	total, err := c.Find(bsonQuery).Count()
	if err != nil || total == 0 {
		return 0, make([]MaintainFixTireListT, 0)
	}

	var res []MaintainFixTireListT
	err = c.Find(bsonQuery).Select(bson.M{"_id": 1, "cid": 1, "tid": 1, "rid": 1, "vid": 1, "cardid": 1, "sn": 1,
		"tno": 1, "type": 1, "cost": 1, "operator": 1, "t": 1}).
		Sort("-_id").Skip(page * 10).Limit(10).All(&res)
	if err != nil {
		return 0, make([]MaintainFixTireListT, 0)
	}

	for i := 0; i < len(res); i++ {
		res[i].Id = res[i].Oid.Hex()
		if res[i].Tid != "" {
			res[i].Team = p.getTeamName(res[i].Tid)
		} else {
			res[i].Team = p.getCompanyName(res[i].Cid)
		}
		if res[i].Vid != "" {
			res[i].Plate, _, _, _, _, _ = p.getPlateByVid(res[i].Vid)
		} else if res[i].Rid != "" {
			res[i].Plate, _, _, _, _, _ = p.getPlateByRid(res[i].Rid)
		}
		res[i].Position = fmt.Sprintf("%d-%d", res[i].CardId, res[i].Sn)
	}

	return total, res
}

func (p *DBOperation) maintainFixTireInfo(id string) (*MaintainFixTireInfoT, error) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireFixes)
	if !bson.IsObjectIdHex(id) {
		return nil, errors.New("无效的参数")
	}
	oid := bson.ObjectIdHex(id)
	bsonQuery := bson.M{"_id": oid}

	var res MaintainFixTireInfoT
	err := c.Find(bsonQuery).One(&res)
	if err != nil {
		return nil, err
	}

	if res.Tid != "" {
		res.Team = p.getTeamName(res.Tid)
	} else {
		res.Team = p.getCompanyName(res.Cid)
	}
	if res.Vid != "" {
		res.Plate, _, _, _, _, _ = p.getPlateByVid(res.Vid)
	} else if res.Rid != "" {
		res.Plate, _, _, _, _, _ = p.getPlateByRid(res.Rid)
	}
	res.Position = fmt.Sprintf("%d-%d", res.CardId, res.Sn)

	return &res, nil
}

func (p *DBOperation) maintainExchangeTire(mft *MaintainExchangeTireT) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireExchanges)
	err := c.Insert(mft)
	if err != nil {
		return err
	}

	if mft.NewTire.Tno != "" {
		p.tireAdd(mft.Operator, mft.Cid, mft.Tid, 0, mft.NewTire.BrandId, mft.NewTire.Model, mft.NewTire.Pattern,
			mft.NewTire.Tno, mft.NewTire.Dot, mft.NewTire.Rfid, mft.NewTire.Depth, mft.NewTire.Status, mft.Date, "")
	}

	c = s.DB(p.dbName).C(CollectionRelations)
	bsonQuery := bson.M{"cardid": mft.CardId, "sn": mft.Sn}
	if mft.Rid != "" {
		bsonQuery["rid"] = mft.Rid
	} else if mft.Vid != "" {
		bsonQuery["vid"] = mft.Vid
	}
	c.Update(bsonQuery, bson.M{"$set": bson.M{"tno": mft.NewTire.Tno}})

	ta := TireActionT{Cid: mft.Cid, Tid: mft.Tid, Rid: mft.Rid, Vid: mft.Vid, Tno: mft.Tno, Operator: mft.Operator,
		Date: mft.Date, Time: mft.Time, T: mft.T, Action: TireActionGetOff, Reason: mft.Remark}
	p.saveTireAction(&ta)

	var wo WorkOrderT
	wo.FromExchangeTire(mft)
	if wo.Tid != "" {
		wo.Team = p.getTeamName(wo.Tid)
	} else {
		wo.Team = p.getCompanyName(wo.Cid)
	}
	wo.Plate, _, _, _, _, _ = p.getPlateByRid(wo.Rid)
	woRec := wo.Records[0]
	wo.Records[0].HasData = p.SensorHasDatas(wo.Rid, woRec.Cardid, woRec.Sn, wo.Date)
	c = s.DB(p.dbName).C(CollectionWorkOrders)
	c.Insert(wo)

	if mft.NewTire.Tno != "" {
		ta.Tno = mft.NewTire.Tno
		ta.Action = TireActionGetOn
		ta.Reason = ""
		p.saveTireAction(&ta)
	}

	return nil
}

func (p *DBOperation) maintainExchangeTireList(userid string, cid int, tid, key string, date, page int) (int, []MaintainExchangeTireListT) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireExchanges)
	bsonQuery := bson.M{}

	if cid == 0 {
		if p.userType(userid) != UserTypeSystemUser {
			return 0, []MaintainExchangeTireListT{} //make([]MaintainExchangeTireListT, 0)
		}
	} else {
		bsonQuery["cid"] = cid
	}

	if tid != "" {
		bsonQuery["tids"] = tid
	}

	if key != "" {
		bsonQuery1 := bson.M{"tno": bson.RegEx{Pattern: key, Options: "im"}}
		bsonQuery2 := bson.M{"rid": bson.RegEx{Pattern: key, Options: "im"}}
		bsonQuery3 := bson.M{"plate": bson.RegEx{Pattern: key, Options: "im"}}
		bsonQuery["$or"] = []bson.M{bsonQuery1, bsonQuery2, bsonQuery3}
	}

	if date > 0 {
		bsonQuery["date"] = date
	}
	total, err := c.Find(bsonQuery).Count()
	if err != nil || total == 0 {
		return 0, []MaintainExchangeTireListT{} // make([]MaintainExchangeTireListT, 0)
	}

	var res []MaintainExchangeTireListT
	err = c.Find(bsonQuery).Select(bson.M{"_id": 1, "cid": 1, "tid": 1, "plate": 1, "tno": 1, "cardid": 1, "sn": 1, "cost": 1, "operator": 1, "t": 1}).
		Sort("-_id").Skip(page * 10).Limit(10).All(&res)
	if err != nil {
		return 0, []MaintainExchangeTireListT{} // make([]MaintainFixTireListT, 0)
	}

	for i := 0; i < len(res); i++ {
		res[i].Id = res[i].Oid.Hex()
		if res[i].Tid != "" {
			res[i].Team = p.getTeamName(res[i].Tid)
		} else {
			res[i].Team = p.getCompanyName(res[i].Cid)
		}
		res[i].Position = fmt.Sprintf("%d-%d", res[i].CardId, res[i].Sn)
		// if res[i].Vid != "" {
		// 	res[i].Plate, _, _, _, _, _ = p.getPlateByVid(res[i].Vid)
		// } else if res[i].Rid != "" {
		// 	res[i].Plate, _, _, _, _, _ = p.getPlateByRid(res[i].Rid)
		// }
	}

	return total, res
}

func (p *DBOperation) maintainExchangeTireInfo(id string) (*MaintainExchangeTireInfoT, error) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireExchanges)
	if !bson.IsObjectIdHex(id) {
		return nil, errors.New("无效的参数")
	}
	oid := bson.ObjectIdHex(id)
	bsonQuery := bson.M{"_id": oid}

	var res MaintainExchangeTireInfoT
	err := c.Find(bsonQuery).One(&res)
	if err != nil {
		return nil, err
	}

	res.Position = fmt.Sprintf("%d-%d", res.CardId, res.Sn)
	if res.Tid != "" {
		res.Team = p.getTeamName(res.Tid)
	} else {
		res.Team = p.getCompanyName(res.Cid)
	}
	if res.Wid != 0 {
		res.Warehouse = p.getWarehouseName(int64(res.Wid))
	}

	return &res, nil
}

func (p *DBOperation) maintainFixValve(mft *MaintainFixValveT) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireFixValves)
	err := c.Insert(mft)
	if err != nil {
		return err
	}

	var wo WorkOrderT
	wo.FromFixValve(mft)
	if wo.Tid != "" {
		wo.Team = p.getTeamName(wo.Tid)
	} else {
		wo.Team = p.getCompanyName(wo.Cid)
	}
	wo.Plate, _, _, _, _, _ = p.getPlateByRid(wo.Rid)
	woRec := wo.Records[0]
	wo.Records[0].HasData = p.SensorHasDatas(wo.Rid, woRec.Cardid, woRec.Sn, wo.Date)
	c = s.DB(p.dbName).C(CollectionWorkOrders)
	c.Insert(wo)

	ta := TireActionT{Cid: mft.Cid, Tid: mft.Tid, Rid: mft.Rid, Vid: mft.Vid, Tno: mft.Tno, Operator: mft.Operator,
		Date: mft.Date, Time: mft.Time, T: mft.T, Action: TireActionFixValve, Reason: mft.Remark}
	p.saveTireAction(&ta)

	return nil
}

func (p *DBOperation) maintainFixValveList(userid string, cid int, tid, key string, date, page int) (int, []MaintainFixValveListT) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireFixValves)
	bsonQuery := bson.M{}

	if cid == 0 {
		if p.userType(userid) != UserTypeSystemUser {
			return 0, []MaintainFixValveListT{}
		}
	} else {
		bsonQuery["cid"] = cid
	}

	if tid != "" {
		bsonQuery["tids"] = tid
	}

	if key != "" {
		bsonQuery1 := bson.M{"tno": bson.RegEx{Pattern: key, Options: "im"}}
		bsonQuery2 := bson.M{"rid": bson.RegEx{Pattern: key, Options: "im"}}
		bsonQuery3 := bson.M{"plate": bson.RegEx{Pattern: key, Options: "im"}}
		bsonQuery["$or"] = []bson.M{bsonQuery1, bsonQuery2, bsonQuery3}
	}

	if date > 0 {
		bsonQuery["date"] = date
	}
	total, err := c.Find(bsonQuery).Count()
	if err != nil || total == 0 {
		return 0, []MaintainFixValveListT{}
	}

	var res []MaintainFixValveListT
	err = c.Find(bsonQuery).Select(bson.M{"_id": 1, "cid": 1, "tid": 1, "plate": 1, "tno": 1, "cardid": 1, "sn": 1, "cost": 1, "operator": 1, "t": 1}).
		Sort("-_id").Skip(page * 10).Limit(10).All(&res)
	if err != nil {
		return 0, []MaintainFixValveListT{}
	}

	for i := 0; i < len(res); i++ {
		res[i].Id = res[i].Oid.Hex()
		if res[i].Tid != "" {
			res[i].Team = p.getTeamName(res[i].Tid)
		} else {
			res[i].Team = p.getCompanyName(res[i].Cid)
		}
		res[i].Position = fmt.Sprintf("%d-%d", res[i].CardId, res[i].Sn)
	}

	return total, res
}

func (p *DBOperation) maintainFixValveInfo(id string) (*MaintainFixValveInfoT, error) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireFixValves)
	if !bson.IsObjectIdHex(id) {
		return nil, errors.New("无效的参数")
	}
	oid := bson.ObjectIdHex(id)
	bsonQuery := bson.M{"_id": oid}

	var res MaintainFixValveInfoT
	err := c.Find(bsonQuery).One(&res)
	if err != nil {
		return nil, err
	}

	res.Position = fmt.Sprintf("%d-%d", res.CardId, res.Sn)
	if res.Tid != "" {
		res.Team = p.getTeamName(res.Tid)
	} else {
		res.Team = p.getCompanyName(res.Cid)
	}

	return &res, nil
}

func (p *DBOperation) maintainInflate(mft *MaintainInflateT) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireInflates)
	err := c.Insert(mft)
	if err != nil {
		return err
	}

	var wo WorkOrderT
	wo.FromInflate(mft) // ExchangeTire(mft)
	if wo.Tid != "" {
		wo.Team = p.getTeamName(wo.Tid)
	} else {
		wo.Team = p.getCompanyName(wo.Cid)
	}
	wo.Plate, _, _, _, _, _ = p.getPlateByRid(wo.Rid)
	woRec := wo.Records[0]
	wo.Records[0].HasData = p.SensorHasDatas(wo.Rid, woRec.Cardid, woRec.Sn, wo.Date)
	c = s.DB(p.dbName).C(CollectionWorkOrders)
	c.Insert(wo)

	ta := TireActionT{Cid: mft.Cid, Tid: mft.Tid, Rid: mft.Rid, Vid: mft.Vid, Tno: mft.Tno, Operator: mft.Operator,
		Date: mft.Date, Time: mft.Time, T: mft.T, Action: TireActionInflate, Reason: mft.Remark}
	p.saveTireAction(&ta)

	return nil
}

func (p *DBOperation) maintainInflateList(userid string, cid int, tid, key string, date, page int) (int, []MaintainInflateListT) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireInflates)
	bsonQuery := bson.M{}

	if cid == 0 {
		if p.userType(userid) != UserTypeSystemUser {
			return 0, []MaintainInflateListT{}
		}
	} else {
		bsonQuery["cid"] = cid
	}

	if tid != "" {
		bsonQuery["tids"] = tid
	}

	if key != "" {
		bsonQuery1 := bson.M{"tno": bson.RegEx{Pattern: key, Options: "im"}}
		bsonQuery2 := bson.M{"rid": bson.RegEx{Pattern: key, Options: "im"}}
		bsonQuery3 := bson.M{"plate": bson.RegEx{Pattern: key, Options: "im"}}
		bsonQuery["$or"] = []bson.M{bsonQuery1, bsonQuery2, bsonQuery3}
	}

	if date > 0 {
		bsonQuery["date"] = date
	}
	total, err := c.Find(bsonQuery).Count()
	if err != nil || total == 0 {
		return 0, []MaintainInflateListT{}
	}

	var res []MaintainInflateListT
	err = c.Find(bsonQuery).Select(bson.M{"_id": 1, "cid": 1, "tid": 1, "plate": 1, "tno": 1, "cardid": 1, "sn": 1, "cost": 1, "operator": 1, "t": 1}).
		Sort("-_id").Skip(page * 10).Limit(10).All(&res)
	if err != nil {
		return 0, []MaintainInflateListT{}
	}

	for i := 0; i < len(res); i++ {
		res[i].Id = res[i].Oid.Hex()
		if res[i].Tid != "" {
			res[i].Team = p.getTeamName(res[i].Tid)
		} else {
			res[i].Team = p.getCompanyName(res[i].Cid)
		}
		res[i].Position = fmt.Sprintf("%d-%d", res[i].CardId, res[i].Sn)
	}

	return total, res
}

func (p *DBOperation) maintainInflateInfo(id string) (*MaintainInflateInfoT, error) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireInflates)
	if !bson.IsObjectIdHex(id) {
		return nil, errors.New("无效的参数")
	}
	oid := bson.ObjectIdHex(id)
	bsonQuery := bson.M{"_id": oid}

	var res MaintainInflateInfoT
	err := c.Find(bsonQuery).One(&res)
	if err != nil {
		return nil, err
	}

	res.Position = fmt.Sprintf("%d-%d", res.CardId, res.Sn)
	if res.Tid != "" {
		res.Team = p.getTeamName(res.Tid)
	} else {
		res.Team = p.getCompanyName(res.Cid)
	}

	return &res, nil
}

type OrderProgressT struct {
	Oid       string `bson:"oid" json:"oid"`
	Status    int    `bson:"status" json:"status"`
	StatusStr string `bson:"-" json:"statusstr"`
	Remark    string `bson:"remark" json:"remark"`
	User      string `bson:"user" json:"user"`
	Name      string `bson:"name" json:"name"`
	T         int64  `bson:"t" json:"t"`
}

func (p *DBOperation) reportAccident(uid string, ra *ReportAccidentT) error {
	s := p.session.Copy()
	defer s.Close()

	ra.Cid, ra.Tid, ra.User, ra.Name = p.getCustomerInfo(uid)
	if ra.Tid != "" {
		ra.TeamName = p.getTeamName(ra.Tid)
	} else {
		ra.TeamName = p.getCompanyName(ra.Cid)
	}
	ra.Did = p.getDriverIdByPhone(ra.Cid, ra.User)

	c := s.DB(p.dbName).C(CollectionReportAccidents)
	c.Insert(ra)

	op := OrderProgressT{
		Oid:    ra.Oid.Hex(),
		Status: 0,
		Remark: ra.Remark,
		User:   ra.User,
		Name:   ra.Name,
		T:      time.Now().Unix(),
	}
	c = s.DB(p.dbName).C(CollectionOrderProgresses)
	c.Insert(op)

	return nil
}

func (p *DBOperation) reportAccidentList(param *ReportAccidentParamT) (int, []ReportAccidentT, error) {
	s := p.session.Copy()
	defer s.Close()

	bsonQuery := bson.M{}
	c := s.DB(p.dbName).C(CollectionReportAccidents)
	if param.Cid != 0 {
		bsonQuery["cid"] = param.Cid
	}

	if param.Tid != "" {
		bsonQuery["tid"] = param.Tid
	}

	if param.Key != "" {
		bsonQuery1 := bson.M{"phone": bson.RegEx{Pattern: param.Key, Options: "im"}}
		bsonQuery2 := bson.M{"name": bson.RegEx{Pattern: param.Key, Options: "im"}}
		bsonQuery3 := bson.M{"plate": bson.RegEx{Pattern: param.Key, Options: "im"}}
		bsonQuery4 := bson.M{"user": bson.RegEx{Pattern: param.Key, Options: "im"}}
		bsonQuery["$or"] = []bson.M{bsonQuery1, bsonQuery2, bsonQuery3, bsonQuery4}
	}

	if param.Date > 0 {
		bsonQuery["date"] = param.Date
	}
	total, err := c.Find(bsonQuery).Count()
	if err != nil || total == 0 {
		return 0, nil, nil
	}

	var res []ReportAccidentT
	c.Find(bsonQuery).Sort("-_id").Skip(param.Page * 10).Limit(10).All(&res)
	return total, res, nil
}

func (p *DBOperation) maintainReportaccidentSetStatus(param *OrderProgressT) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReportAccidents)
	_id := bson.ObjectIdHex(param.Oid)
	c.Update(bson.M{"_id": _id}, bson.M{"$set": bson.M{"status": param.Status}})

	c = s.DB(p.dbName).C(CollectionOrderProgresses)
	c.Insert(param)

	return nil
}

func (p *DBOperation) maintainReportaccidentProgrss(oid string) ([]OrderProgressT, error) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionOrderProgresses)
	var res []OrderProgressT
	err := c.Find(bson.M{"oid": oid}).Sort("-_id").All(&res)
	for i := 0; i < len(res); i++ {
		res[i].StatusStr = p.orderStatusToStr(res[i].Status)
	}

	return res, err
}

var OrderStatusStrT map[int]string = map[int]string{
	0: "待审核",
	1: "审核通过",
	2: "审核不通过",
	3: "已通知维护人员",
	4: "维修完成",
	5: "完成",
}

func (p *DBOperation) orderStatusToStr(stat int) string {
	if str, ok := OrderStatusStrT[stat]; ok {
		return str
	}
	return "未知状态"
}

func (p *DBOperation) getCustomerInfo(uid string) (cid int, tid string, user, name string) {
	s := p.session.Copy()
	defer s.Close()

	var res struct {
		Cid  int    `bson:"cid"`
		Tid  string `bson:"tid"`
		User string `bson:"user"`
		Name string `bson:"uname"`
	}

	c := s.DB(p.dbName).C(CollectionCustomers)
	oid := bson.ObjectIdHex(uid)
	err := c.Find(bson.M{"_id": oid}).Select(bson.M{"_id": 0, "cid": 1, "tid": 1, "user": 1, "uname": 1}).One(&res)
	if err == nil {
		return res.Cid, res.Tid, res.User, res.Name
	}
	return
}

func (p *DBOperation) getDriverIdByPhone(cid int, phone string) string {
	s := p.session.Copy()
	defer s.Close()

	var res map[string]string
	c := s.DB(p.dbName).C(CollectionDrivers)
	err := c.Find(bson.M{"cid": cid, "phone": phone}).Select(bson.M{"_id": 0, "did": 1}).One(&res)
	if err != nil {
		return ""
	}
	return res["did"]
}

func (p *DBOperation) getTireStatus(cid int, tno string) (int, int) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTires)
	var res map[string]int

	err := c.Find(bson.M{"cid": cid, "tno": tno}).Select(bson.M{"_id": 0, "status": 1, "ma": 1}).One(&res)
	if err != nil {
		return TireStatusUnknow, 0
	}
	return res["status"], res["ma"]
}

func (p *DBOperation) SaveCustomerWechatInfo(userid, wxId, wxName, wxHeadImgURL string) {
	s := p.session.Copy()
	defer s.Close()

	oi := bson.ObjectIdHex(userid)
	c := s.DB(p.dbName).C(CollectionCustomers)

	c.Update(bson.M{"_id": oi}, bson.M{"$set": bson.M{"wxid": wxId, "wxname": wxName, "wxheadimgurl": wxHeadImgURL}})
}

func (p *DBOperation) tireImport(ti *TireImportT) error {
	errTireNos := make([]string, 0)
	var err error

	tids := []string{}
	if ti.Tid != "" {
		tids = p.getTeamParents(ti.Tid)
	}

	for _, tire := range ti.Tires {
		if tire.No != "" {
			err = p.tireImportOne(ti.Cid, ti.Tid, tids, &tire)
			if err != nil {
				errTireNos = append(errTireNos, tire.No+err.Error())
			}
		}
	}
	if len(errTireNos) == 0 {
		return nil
	}

	sErr := strings.Join(errTireNos, "\r\n")
	//sErr = fmt.Sprint("轮胎导入有", len(errTireNos), "条错误：", sErr)
	return errors.New(sErr)
}

func (p *DBOperation) tireImportOne(cid int, tid string, tids []string, tio *TireImprtOneT) error {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTires)

	err := c.Find(bson.M{"cid": cid, "tno": tio.No}).Select(bson.M{"_id": 1}).One(nil)
	if err == nil {
		return errors.New("重复的胎号")
	}

	var wid int64
	if tio.Storeage != "" {
		wid = p.getWarehouseID(cid, tid, tio.Storeage)
		if wid == 0 {
			return errors.New("系统中未录入“" + tio.Storeage + "”仓库")
		}
	}
	status := 0
	switch tio.Status {
	case "新胎":
		status = 0
	case "周转胎":
		status = 1
	case "翻新胎":
		status = 2
	case "报废胎":
		status = 3
	case "待维修":
		status = 4
	default:
		//status = -1
		return errors.New("无效的轮胎状态")
	}
	brand := p.getTireBrandIdByName(cid, tio.Brand)
	if brand == 0 {
		return errors.New("系统中无此轮胎品牌")
	}
	if !p.checkTireModelAndPattern(cid, brand, tio.Model, tio.Pattern) {
		return errors.New("系统中无此轮胎型号与花纹")
	}
	intodate := today(0)

	reason := "批量导入"
	aCpdepths := []float32{tio.Depth}

	bsonData := bson.M{"cid": cid, "tid": tid, "tids": tids, "tno": tio.No, "mid": tio.Model, "pattern": tio.Pattern,
		"dot": tio.Dot, "rfid": tio.Rfid, "pdepth": tio.Depth, "cpdepths": aCpdepths, "reason": reason}
	bsonData["wid"] = wid
	bsonData["bid"] = brand
	bsonData["status"] = status
	bsonData["intodate"] = intodate

	err = c.Insert(bsonData)
	if err != nil {
		return err
	}

	ta := TireActionT{Cid: cid, Tid: tid, Wid: int(wid), Rid: "", Tno: tio.No, T: time.Now().Unix(), Date: intodate,
		Action: TireActionStockIn, Cpdepths: aCpdepths, Reason: reason, Status: status, Operator: tio.Operator}
	p.saveTireAction(&ta)

	return nil
}

func (p *DBOperation) checkTireModelAndPattern(cid int, tbid int, model, pattern string) bool {
	if model == "" && pattern == "" {
		return false
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTireModels)
	err := c.Find(bson.M{"cid": cid, "tbid": tbid, "tmid": model, "pattern": pattern}).
		Select(bson.M{"_id": 1}).One(nil)
	return err == nil
}

func (p *DBOperation) teamBelongCompay(cid int, tid string) bool {
	if tid == "" {
		return true
	}

	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionTeams)
	err := c.Find(bson.M{"cid": cid, "tid": tid}).Select(bson.M{"_id": 1}).One(nil)

	return err == nil
}

func (p *DBOperation) tireAssign(cid int, tid string, tnos []string) error {
	if len(tnos) == 0 {
		return nil
	}

	s := p.session.Copy()
	defer s.Close()

	tids := p.getTeamParents(tid)
	c := s.DB(p.dbName).C(CollectionTires)
	bsonQuery := bson.M{"cid": cid, "tno": bson.M{"$in": tnos}}
	_, err := c.UpdateAll(bsonQuery, bson.M{"$set": bson.M{"tid": tid, "tids": tids}})
	return err
}

func (p *DBOperation) saveReceiverThreshold(rid string, pressureThreshold [5][2]float32, temperatureThreshold int) {
	s := p.session.Copy()
	defer s.Close()

	c := s.DB(p.dbName).C(CollectionReceivers)
	c.Update(bson.M{"rid": rid}, bson.M{"$set": bson.M{"threshold.pres": pressureThreshold, "threshold.temp": temperatureThreshold}})
}
